shoplifting-watcher

Watch shoplifting status for players.

目前為 2024-01-13 提交的版本,檢視 最新版本

// ==UserScript==
// @name         shoplifting-watcher
// @namespace    nodelore.torn.shoplifting-watcher
// @version      0.2
// @description  Watch shoplifting status for players.
// @author       nodelore[2786679]
// @match        https://www.torn.com/*
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function(){
    'use strict';

    if(window.SHOPLIFTING_WATCHER){
        return;
    }
    window.SHOPLIFTING_WATCHER = true;

    const update_config = ()=>{
        localStorage.setItem(CONFIG_STORAGE_KEY, JSON.stringify(watcher_config));
    }

    // ============================= Configuration ==============================
    let API = localStorage.getItem("APIKey") || "";
    const CONFIG_STORAGE_KEY = "SHOPLIFTING_WATCHER"
    let watcher_config = {
        interval: 60, // second,
        enabled: [],
        collapsed: false,
        disabled: false,
        offset: [30, 30],
    }
    // ==========================================================================
    let inPDA = false;
    const PDAKey = "###PDA-APIKEY###";
    if(PDAKey.charAt(0) !== "#"){
        inPDA = true;
        if(!API){
            API = PDAKey;
        }
    }
    if(localStorage.getItem(CONFIG_STORAGE_KEY)){
        const config = JSON.parse(localStorage.getItem(CONFIG_STORAGE_KEY));
        if(config["collapsed"] === undefined){
            update_config();
        } else{
            watcher_config = config;
        }
    }

    if(API && !localStorage.getItem("APIKey")){
        localStorage.setItem("APIKey", API);
    }

    const notify = (notification)=>{
        if(inPDA){
            alert(notification);
            return;
        }
        try{
            if (Notification.permission === "granted") {
                new Notification(notification);
            } 
            else if (Notification.permission !== "denied") {
                Notification.requestPermission().then(function (permission) {
                  if (permission === "granted") {
                    new Notification(notification);
                  }
                });
            }
        } catch(e){
        }
    }

    const addStyle = ()=>{
        const styles = `
            .dark-mode #shoplifting-body *{
                color: #000;
            }
            
            .dragging{
                opacity: .5;
            }

            .collapsed .shoplifting-item:not(.active){
                display: none;
            }

            .collapsed .shoplifting-item-detail:not(.active){
                display: none;
            }
        
            #shoplifting-body{
                display: flex;
                position: fixed;
                width: 300px;
                height: auto;
                background: #FFF;
                border-radius: 6px;
                box-sizing: border-box;
                padding: 10px 10px 0 10px;
                flex-flow: column nowrap;
                z-index: 1000000;
            }

            #shoplifting-body *{
                user-select: none;
            }

            #shoplifting-body.hidden{
                display: none !important;
            }

            .shoplifting-title{
                display: flex;
                flex-flow: row nowrap;
                align-items: center;
                margin-bottom: 10px;
            }

            .shoplifting-title div.heading{
                font-size: 15px;
                font-weight: bold;
                cursor: grab;
            }

            .shoplifting-title div.close-btn{
                margin-left: auto;
                cursor: pointer !important;;
            }

            .shoplifting-status{
                width: 100%;
                display: flex;
                flex-flow: column nowrap;
                flex: 1;
            }

            .shoplifting-item{
                width: 100%;
                display: flex;
                flex-flow: column nowrap;
                border-top: 1px solid rgba(1, 1, 1, .1);
                box-sizing: border-box;
                padding: 5px 0;
            }

            .shoplifting-item-info{
                display: flex;
                flex-flow: column nowrap;
            }

            .shoplifting-item-name{
                font-weight: bold;
                font-size: 14px;
                margin-bottom: -3px;
            }

            .shoplifting-item-detail{
                display: flex;
                align-items: center;
                margin-top: 3px;
            }

            .shoplifting-item-detail-name{
                font-size: 13px;
            }

            .shoplifting-item-toggle{
                display: flex;
                margin-left: auto;
                cursor: pointer;
                height: 100%;
            }

            .shoplifting-item-toggle div{
                width: 60px;
                height: 20px;
                line-height: 20px;
                box-shadow: 0 0 6px 3px rgba(1, 1, 1, .1);
                text-align: center;
                font-weight: bold;
                border-radius: 3px;
                color: #FFF;
                transition: .15s all ease-in-out;
                opacity: .3;
            }

            .shoplifting-item-toggle div.active{
                opacity: 1 !important;
            }

            .shoplifting-item-toggle div.active{
                opacity: 1;
            }

            .shoplifting-item-toggle div:hover{
                opacity: 1;
            }

            .shoplifting-item-toggle-on{
                background: #82c91e;
            }

            .shoplifting-item-toggle-off{
                background: #E54C19;
            }

            .shoplifting-apiusage{
                display: flex;
                align-items: center;
                border-top: 1px solid rgba(1, 1, 1, .1);
                box-sizing: border-box;
                padding: 5px 0 5px 0;
            }

            .shoplifting-apiusage div{
                font-weight: bold;
                font-size: 14px;
            }
            .shoplifting-apiusage input{
                color: rgba(1, 1, 1, .5);
                height: 20px;
                line-height: 20px;
                margin-left: auto;
                width: 120px;
                background: #F2F2F2;
                text-align: center;
                font-weight: bold;
            }

            .toggle-btn{
                position: relative;
            }

            #toggle-watcher{
                display: none;
            }

            #toggle-watcher:checked + label{
                background: #82c91e; 
            }

            #toggle-watcher:checked + label:after{
                left: calc(100% - 15px);
            }

            #toggle-watcher + label{
                display: inline-block;
                width: 40px;
                height: 15px;
                position: relative;
                transition: 0.15s;
                margin: 0px 20px;
                box-sizing: border-box;

                background: #ddd;
                border-radius: 20px;
                box-shadow: 1px 1px 3px #aaa;
            }

            #toggle-watcher + label:after{
                content: '';
                display: block;
                position: absolute;
                left: 0px;
                top: 0px;
                width: 15px;
                height: 15px;
                transition: 0.15s;
                cursor: pointer;

                background: #fff;
                border-radius: 50%;
                box-shadow: 1px 1px 3px #aaa;
            }

            .shoplifting-collapsed{
                padding: 5px 0 5px 0;
                background: #F2F2F2;
                text-align: center;
                border-top: 1px solid rgba(1, 1, 1, .1);
                font-weight: bold;
                transition: .15s all ease-in-out;
            }

            .shoplifting-collapsed:hover{
                background: #FFF;
                cursor: pointer;
            }
        `;
        const isTampermonkeyEnabled = typeof unsafeWindow !== 'undefined';
        if (isTampermonkeyEnabled){
            GM_addStyle(styles);
        } else {
            let style = document.createElement("style");
            style.type = "text/css";
            style.innerHTML = styles;
            document.head.appendChild(style);
        }
    }

    addStyle();

    let watcher_interval;
    let icon_interval;
    const insert_icon = ()=>{
        if($("ul[class*=status-icons]").length === 0){
            if(!icon_interval){
                icon_interval = setInterval(()=>{
                    insert_icon();
                    icon_interval = null;
                }, 500)
            }
            return;
        }
        if($("ul[class*=status-icons]").find(".shoplifting_watcher").length === 0){
            const icon = $("<li class='shoplifting_watcher' title='Shoplifting Watcher'></li>");
            icon.css({
                "background-image": "url(/images/v2/editor/emoticons.svg)",
                "cursor": "pointer",
                "background-position": "-74px -42px"
            });
            icon.click(function(){
                if($("div#shoplifting-body").hasClass("hidden")){
                    $("div#shoplifting-body").removeClass("hidden");
                } else{
                    $("div#shoplifting-body").addClass("hidden");
                }
                
            })
            $("ul[class*=status-icons]").prepend(icon);
        }
    }

    const update_watcher = ()=>{
        if(!API){
            return;
        }
        let update_flag = false;
        if($("#shoplifting-body .shoplifting-status div.shoplifting-item").length > 0){
            update_flag = true;
        }
        fetch(`https://api.torn.com/torn/?selections=shoplifting&key=${API}`).then((res)=>{
            if(res.ok){
                res.json().then((data)=>{
                    let notification = "";
                    const shoplifting_data = data["shoplifting"];
                    for(let shop_name in shoplifting_data){
                        const shop_status = shoplifting_data[shop_name];
                        if(!update_flag){
                            const shoplifting_item = $(`
                                <div class="shoplifting-item" data-shop="${shop_name}">
                                    <div class="shoplifting-item-name">${shop_name}</div>
                                </div>
                            `);

                            let active_flag = false;
                            for(let detail of shop_status){
                                const detail_item = $(`<div class="shoplifting-item-detail"></div>`)
                                let prefix = ""
                                const key = `${shop_name}_${detail["title"].toLowerCase().replace(" ", "_")}`;
                                if(detail["disabled"]){
                                    prefix = "❌";
                                    if(watcher_config.enabled.indexOf(key) !== -1){
                                        if(notification.length > 0){
                                            notification += "\n";
                                        }
                                        notification += `【${shop_name}】【${detail["title"]}】 is disabled`;
                                    }
                                } else{
                                    prefix = "✅";
                                }
                                detail_item.append($(`<div class="shoplifting-item-detail-name" data-key="${key}">${prefix} ${detail["title"]}</div>`));
                                
                                let toggleOn = "";
                                let toggleOff = "";
                                if(watcher_config.enabled.indexOf(key) !== -1){
                                    toggleOn = " active";
                                    detail_item.addClass("active");
                                    active_flag = true;
                                } else{
                                    toggleOff = " active";
                                }
                                const toggle = $(`
                                    <div class="shoplifting-item-toggle" data-key="${key}">
                                        <div class="shoplifting-item-toggle-on${toggleOn}">ON</div>
                                        <div class="shoplifting-item-toggle-off${toggleOff}">OFF</div>
                                    </div>`
                                );
        
                                toggle.click(function(){
                                    const key = $(this).attr("data-key");
                                    const parent = $(this).parent();
                                    const item = parent.parent();
                                    if(watcher_config.enabled.indexOf(key) !== -1){
                                        const index = watcher_config.enabled.indexOf(key);
                                        watcher_config.enabled.splice(index, 1);
                                        $(`div.shoplifting-item-toggle[data-key=${key}] .shoplifting-item-toggle-off`).addClass("active");
                                        $(`div.shoplifting-item-toggle[data-key=${key}] .shoplifting-item-toggle-on`).removeClass("active");
                                        parent.removeClass("active");
                                        let clear_flag = true;
                                        item.find(".shoplifting-item-detail").each(function(){
                                            if($(this).hasClass("active")){
                                                clear_flag = false;
                                            }
                                        });
                                        if(clear_flag){
                                            item.removeClass("active");
                                        }
                                    } else{
                                        watcher_config.enabled.push(key);
                                        $(`div.shoplifting-item-toggle[data-key=${key}] .shoplifting-item-toggle-off`).removeClass("active");
                                        $(`div.shoplifting-item-toggle[data-key=${key}] .shoplifting-item-toggle-on`).addClass("active");
                                        
                                        if(!parent.hasClass("active")){
                                            parent.addClass("active");
                                        }
                                        if(!item.hasClass("active")){
                                            item.addClass("active");
                                        }
                                    }
                                    update_config();
                                });
                                detail_item.append(toggle);
                                
                                shoplifting_item.append(detail_item)
                            }
                            
                            if(active_flag){
                                shoplifting_item.addClass("active");
                            }
                            $("#shoplifting-body").find(".shoplifting-status").append(shoplifting_item);
                        }
                        else{
                            for(let detail of shop_status){
                                let prefix = "";
                                const key = `${shop_name}_${detail["title"].toLowerCase().replace(" ", "_")}`;
                                if(detail["disabled"]){
                                    prefix = "❌";
                                    if(watcher_config.enabled.indexOf(key) !== -1){
                                        if(notification.length > 0){
                                            notification += "\n";
                                        }
                                        notification += `【${shop_name}】【${detail["title"]}】 is disabled`;
                                    }
                                } else{
                                    prefix = "✅";
                                }

                                const target = $(`.shoplifting-item-detail-name[data-key="${key}"]`);
                                target.text(`${prefix} ${detail["title"]}`);
                            }
                        }

                    }

                    if(notification.length > 0){
                        notify(notification);
                        $(".shoplifting_watcher").attr("title", `Shoplifting Watcher\n${notification}`)
                    }
                });
            }
        });
    }

    let is_dragging = false;
    let offset = watcher_config.offset;
    const insert_body = ()=>{
        const collapsed_class = watcher_config.collapsed ? " collapsed" : "";

        const watcher = $(`<div id="shoplifting-body" class="hidden${collapsed_class}">
            <div class="shoplifting-status">
            </div>
            <div class="shoplifting-apiusage">
                <div>Query interval: </div>
            </div>
        </div>`);

        watcher.offset({
            left: offset[0],
            top: offset[1],
        });
        
        const input = $(`<input type="number" class="shoplifting-interval-input" step="1" value="${watcher_config.interval}"/>`);
        input.keyup(function(){
            const new_val = parseInt($(this).val());
            if(new_val !== watcher_config.interval){
                watcher_config.interval = new_val;
                if(watcher_interval){
                    clearInterval(watcher_interval);
                    watcher_interval = setInterval(()=>{
                        update_watcher();
                    }, watcher_config.interval*1000)
                }
                update_config();
            }
        })

        watcher.find(".shoplifting-apiusage").append(input);

        let title_content = "Shoplifting watcher";
        if(!API){
            title_content = "No Public API"
        }
        const title = $(`
            <div class="shoplifting-title">
                
            </div>`
        );

        const heading = $(`<div class="heading">${title_content}</div>`);
        heading.mousedown(function(e){
            $("#shoplifting-body").addClass("dragging");
            is_dragging = true;
            offset = [
                $("#shoplifting-body").offset().left - e.pageX,
                $("#shoplifting-body").offset().top - e.pageY
            ]
        });

        heading.mousemove(function(e){
            if(is_dragging){
                $("#shoplifting-body").offset({
                    left: e.pageX + offset[0],
                    top: e.pageY + offset[1]
                })
            }
        })

        heading.mouseup(function(){
            $("#shoplifting-body").removeClass("dragging");
            is_dragging = false;
            watcher_config.offset = [$("#shoplifting-body").offset().left, $("#shoplifting-body").offset().top];
            update_config();
        });

        watcher.mouseleave(function(){
            $("#shoplifting-body").removeClass("dragging");
            is_dragging = false;
            watcher_config.offset = [$("#shoplifting-body").offset().left, $("#shoplifting-body").offset().top];
            update_config();
        })

        title.append(heading);

        const checked = watcher_config.disabled ? "" : "checked";

        const disabled_btn = $(`<div class="toggle-btn">
            <input type="checkbox" id="toggle-watcher" ${checked}>
            <label for="toggle-watcher"></label>
        </div>`);

        disabled_btn.find("#toggle-watcher").change(function(){
            const status = this.checked;
            if(status === true){
                update_watcher();
                if(!watcher_interval){
                    watcher_interval = setInterval(()=>{
                        update_watcher();
                    }, watcher_config.interval*1000);
                }
            } else{
                if(watcher_interval){
                    clearInterval(watcher_interval);
                    watcher_interval = null;
                    $("div.shoplifting-item").each(function(){
                        $(this).remove();
                    });
                }
            }
            watcher_config.disabled = !status;
            update_config();
        });

        title.append(disabled_btn);

        const close_btn = $(`<div class='close-btn' title="Click to close">❌</div>`);

        close_btn.click(function(){
            $("div#shoplifting-body").addClass("hidden");
        });

        title.append(close_btn);
        watcher.prepend(title);

        const collapsed = $(`<div class="shoplifting-collapsed">${watcher_config.collapsed ? "Expand" : "Collapsed"}</div>`);
        collapsed.click(function(){
            if(watcher_config.collapsed === true){
                watcher_config.collapsed = false;
                $(this).text("Collapsed");
                $("#shoplifting-body").removeClass("collapsed");
            } else{
                watcher_config.collapsed = true;
                $(this).text("Expand");
                $("#shoplifting-body").addClass("collapsed");
            }

            update_config();
        })

        watcher.append(collapsed);

        $(body).append(watcher);

        if(!watcher_config.disabled){
            update_watcher();
            if(!watcher_interval){
                watcher_interval = setInterval(()=>{
                    update_watcher();
                }, watcher_config.interval*1000);
            }
    
        }

        insert_icon();

    }

    insert_body();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址