Wolfery Audio Notifier

Plays a sound when a mention occurs, or when you are whispered, directly messaged, or addressed.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Wolfery Audio Notifier
// @name:de      Wolfery Audio Benachrichtigungen
// @namespace    https://forum.wolfery.com/u/felinex/
// @version      1.5
// @description  Plays a sound when a mention occurs, or when you are whispered, directly messaged, or addressed.
// @description:de Spielt einen Sound ab, wenn eine Erwähnung (Mention) auftaucht, man angeflüstert, direkt angeschrieben (message) oder adressiert wird.
// @icon         https://static.f-list.net/images/eicon/wolfery.png
// @license      All Rights Reserved
// @author       Felinex Gloomfort
// @match        https://wolfery.com/*
// @match        https://test.wolfery.com/*
// @match        https://*.mucklet.com/*
// @icon
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log("[AudioNotifier] Script loaded.");

    const SOUND_URL = 'https://actions.google.com/sounds/v1/alarms/beep_short.ogg';
    const audio = new Audio(SOUND_URL);
    audio.volume = 0.5;

    let lastPlay = 0;
    let initAttempts = 0;

    function init() {
        initAttempts++;
        if (typeof window.app === 'undefined') {
            if (initAttempts < 60) {
                setTimeout(init, 500);
            } else {
                console.error("[AudioNotifier] ERROR: window.app was not found.");
            }
            return;
        }

        console.log(`[AudioNotifier] window.app found! Trying to load module 'charLog' (Attempt ${initAttempts})...`);

        // Using getModule to fetch the module once the client initialized it.
        // This avoids the "App.require may only be called from an AppModule's constructor" error.
        const charLog = window.app.getModule('charLog');

        if (!charLog) {
            // Module is not ready yet, keep waiting
            if (initAttempts < 60) {
                setTimeout(init, 500);
            } else {
                console.error("[AudioNotifier] ERROR: 'charLog' module could not be loaded even after 30 seconds.");
            }
            return;
        }

        console.log("[AudioNotifier] Module 'charLog' successfully loaded. Adding EventModifier...");

        try {
            charLog.addEventModifier({
                id: 'userscriptSoundNotifier',
                sortOrder: 100,
                callback: (ev, ctrl, mod) => {

                    console.log(`[AudioNotifier] Event received: ${ev.type}`, { event: ev, mod: mod, ctrlId: ctrl.id });

                    // Exclude muted events and own character's actions
                    if (mod.muted) return;
                    if (ev.char && ev.char.id === ctrl.id) return;

                    // 1. Check for mentions (Set by the system when highlight triggers match)
                    const isMention = !!mod.mentioned;

                    // 2. Target check (Is the character the target of a whisper/message/address?)
                    // We manually check the target attributes of the original event
                    let isTargetedToMe = false;
                    const isDirectType = ['whisper', 'message', 'address'].includes(ev.type);

                    if (isDirectType) {
                        // Either it is explicitly in the mod object (set by previous modifiers)
                        if (mod.targeted) {
                            isTargetedToMe = true;
                        }
                        // Or we look for the character directly in the event targets
                        else if (ev.target && ev.target.id === ctrl.id) {
                            isTargetedToMe = true;
                        }
                        else if (ev.targets && Array.isArray(ev.targets)) {
                            // For group messages (multiple targets)
                            if (ev.targets.some(t => t.id === ctrl.id)) {
                                isTargetedToMe = true;
                            }
                        }
                    }

                    console.log(`[AudioNotifier] Evaluation: Mention=${isMention}, Targeted=${isTargetedToMe}`);

                    // Trigger sound
                    if (isMention || isTargetedToMe) {
                        playSound();
                    }
                }
            });
            console.log("[AudioNotifier] EventModifier successfully registered!");
        } catch (err) {
            console.error("[AudioNotifier] ERROR registering EventModifier:", err);
        }
    }

    function playSound() {
        const now = Date.now();
        if (now - lastPlay < 1000) return; // Spam protection / throttling

        lastPlay = now;

        audio.play().then(() => {
            console.log("[AudioNotifier] Sound played!");
        }).catch(e => {
            console.error("[AudioNotifier] ERROR playing sound. Browser blocking autoplay? Click anywhere on the page.", e);
        });
    }

    // Catch first click to unlock browser autoplay restrictions
    document.addEventListener('click', function unlockAudio() {
        audio.play().then(() => { audio.pause(); audio.currentTime = 0; }).catch(() => {});
        document.removeEventListener('click', unlockAudio);
    }, { once: true });

    // Wait briefly for the DOM loading process to begin before starting
    setTimeout(init, 1000);
})();