Wolfery Audio Notifier

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

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==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);
})();