Camamba Chat Helpers

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

As of 22.03.2021. See ბოლო ვერსია.

ეს სკრიპტი არ უნდა იყოს პირდაპირ დაინსტალირებული. ეს ბიბლიოთეკაა, სხვა სკრიპტებისთვის უნდა ჩართეთ მეტა-დირექტივაში // @require https://update.greatest.deepsurf.us/scripts/423722/913809/Camamba%20Chat%20Helpers.js.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Camamba Chat Helpers
// @namespace    dannysaurus.camamba
// @version      0.1
// @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 decorateUsersObj(users = {}) {

        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).forEach(u => {
                if(userPredicateFnc(u)) {
                    result.push(u);
                } else {
                    excluded.push(u);
                }
            });

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

            return decorateUsersObj(result);
        };

        const byId = (id) => by(u => u.id == id);

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

        const byGender = (gender) => {
            const genderLower = String(gender).toLowerCase();
            return by(u => u.gender.toLowerCase().startsWIth(genderLower));
        };

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

            const cammedUsersIds = new Set(Object.values(camData).map(camData => String(camData.user)));

            return (u => cammedUsersIds.has(String(u.id)), takeWhenFalse);
        };

        const byPos = (pos) => toArray()[pos];

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

        const restore = () => {
            toArray().forEach(user => {
                if (!user.original) return;

                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,
            byName,
            byGender,
            byPos,
            byIsCammed,
            byIsNotCammed: () => byIsCammed().excluded,
            save,
            restore
        }).map(([propName, value]) => {
            return [propName, { value, configurable: true }];
        })));
    }

    function decorateRoomsObj(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 => decorateUsersObj(users));
    patchObject(() => rooms, rooms => decorateRoomsObj(rooms));
})();