Wolfery Audio Notifier

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

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

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