Greasy Fork

Camamba Chat Helpers

decorates "knownUsers" and "rooms" objects with functions useful for console and other scripts

目前为 2021-03-26 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.greasyfork.icu/scripts/423722/915087/Camamba%20Chat%20Helpers.js

// ==UserScript==
// @name         Camamba Chat Helpers
// @namespace    dannysaurus.camamba
// @version      0.1.4
// @description  decorates "knownUsers" and "rooms" objects with functions useful for console and other scripts
// @license      MIT License
// @include      https://www.camamba.com/chat/
// @include      https://www.de.camamba.com/chat/
// @include      https://www.camamba.com/chat/
// @include      https://www.de.camamba.com/chat/
// @grant        none
// ==/UserScript==

/* jslint esversion: 9 */
/* global me, camData, rooms, blockList, friendList, friendRequests, adminMessages, jsLang, byId, myRooms, knownUsers, activeRoom, selectedUser, settings, onMessageHandlers, postMessageHandlers */

(function() {
    function decorateUsers(users = {}) {
        
        const isUser = (user) => {
            return user.id;
        };

        const toArray = () => {
            if (Array.isArray(users)) {
                return [...users];
            }

            if (users.id && users.name) {
                return [ users ];
            }

            return Object.values(users);
        };

        const toString = () => {
            return toArray().map(u => {

                return Object.entries(u)
                    .map(([prop, val]) => prop + ':' + val)
                    .join('\t');

            }).join('\n');
        };

        const by = (userPredicateFnc) => {
            const result = [], excluded = [];

            Object.values(users).filter(u => isUser(u)).forEach(u => {
                if(userPredicateFnc(u)) {
                    result.push(u);
                } else {
                    excluded.push(u);
                }
            });

            if (excluded.length) {
                result.excluded = decorateUsers(excluded);
                result.excludedAll = decorateUsers([ ...excluded, ...users.excludedAll ]);
            }

            return decorateUsers(result);
        };

        const byId = (id) => {
            return by(user => user.id == id);
        };

        const byName = (name) => {
            const nameLower = String(name).toLowerCase();
            return by(user => {
                return user.name.toLowerCase().includes(nameLower);
            });
        };

        const byGender = (gender) => {
            const genderLower = String(gender).toLowerCase();
            return by(user => {
                return user.gender.toLowerCase().startsWIth(genderLower);
            });
        };
        
        const bySelected = () => {
            const selectedUserId = selectedUser ? selectedUser.dataset.id : 0;
            
            if (!selectedUserId) {
                return by(user => false);
            }
            
            return byId(selectedUserId);
        };

        const byIsCammed = () => {
            if (!camData) return false;

            const camDataUserIds = new Set(
                Object.values(camData)
                    .filter(cd => cd.user)
                    .map(cd => String(cd.user))
            );

            return by(user => {
                return camDataUserIds.has(String(user.id));
            });
        };

        const byViewing = () => {
            return users.by(user => {
                return user.viewing;
            });
        };
        
        const byPos = (pos) => {
            return toArray()[pos];
        };

        const stopViewing = () => {
            return byViewing().forEach(user => {
                janusSend('remove', user.id);
            });
        };

        const save = () => toArray().forEach(user => {
            user.original = {...user};
        });

        const restore = () => by(user => user.original).forEach(user => {
            Object.assign(user, user.original);
            delete user.original;
        });

        return Object.defineProperties(users, Object.fromEntries(Object.entries({
            excluded: users.excluded || [],
            excludedAll: users.excludedAll || [],
            toArray,
            toString,
            
            by,
            
            byId,
            bySelected,
            byName,
            byGender,
            byPos,
            byIsCammed,
            byIsNotCammed: () => byIsCammed().excluded,
            byViewing,
            
            stopViewing,
            
            save,
            restore
        }).map(([propName, value]) => {
            return [propName, { value, configurable: true }];
        })));
    }

    function decorateRooms(rooms = {}) {
        const roomsByName = (name) => {
            const nameLower = String(name).toLowerCase();

            const result = {};

            Object.entries(rooms).forEach(([roomId, roomName]) => {

                if (roomName.toLowerCase().includes(nameLower)) {
                    result[roomId] = roomName;
                }
            });

            return result;
        };

        return Object.defineProperties(rooms, {
            byName: { value: roomsByName, configurable: true },
        });
    }

    const patchObject = function(getExpectedObjFnc, patchFnc, timeOutRetryMillis = 200, maxPeriodTryMillis = 5000) {
        const expectedObj = getExpectedObjFnc();

        if (!expectedObj && timeOutRetryMillis <= maxPeriodTryMillis) {
            setTimeout(() => patchObject(getExpectedObjFnc, patchFnc, timeOutRetryMillis), maxPeriodTryMillis - timeOutRetryMillis);
            return;
        }
        patchFnc(expectedObj);
    };

    patchObject(() => knownUsers, users => decorateUsers(users));
    patchObject(() => rooms, rooms => decorateRooms(rooms));
})();