data-manager2

process html, store and filter data

Этот скрипт недоступен для установки пользователем. Он является библиотекой, которая подключается к другим скриптам мета-ключом // @require https://update.greasyfork.org/scripts/548610/1656007/data-manager2.js

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         data-manager2
// @namespace    Violentmonkey Scripts
// @version      1.5
// @license      MIT
// @description  process html, store and filter data
// @author       smartacephale
// @match        *://*/*
// @grant        unsafeWindow
// @grant        GM_addStyle
// @downloadURL https://update.greasyfork.org/scripts/494204/data-manager.user.js
// @updateURL https://update.greasyfork.org/scripts/494204/data-manager.meta.js
// ==/UserScript==

class DataFilter {
    constructor(rules, state) {
        this.state = state;
        this.rules = rules;

        const methods = Object.getOwnPropertyNames(this);
        this.filters = methods.reduce((acc, k) => {
            if (k in this.state) {
                acc[k] = this[k];
                GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
            }
            return acc;
        }, {});
    }

    filterPublic = () => {
        return (v) => {
            const isPublic = !this.rules.IS_PRIVATE(v.element);
            return {
                tag: 'filter-public',
                condition: this.state.filterPublic && isPublic
            };
        }
    }

    filterPrivate = () => {
        return (v) => {
            const isPrivate = this.rules.IS_PRIVATE(v.element);
            return {
                tag: 'filter-private',
                condition: this.state.filterPrivate && isPrivate
            };
        }
    }

    filterDuration = () => {
        return (v) => {
            const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
            return {
                tag: 'filter-duration',
                condition: this.state.filterDuration && notInRange
            };
        }
    }

    filterExclude = () => {
        const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
        return (v) => {
            const containTags = tags.some(tag => tag.test(v.title));
            return {
                tag: 'filter-exclude',
                condition: this.state.filterExclude && containTags
            };
        }
    }

    filterInclude = () => {
        const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
        return (v) => {
            const containTagsNot = tags.some(tag => !tag.test(v.title));
            return {
                tag: 'filter-include',
                condition: this.state.filterInclude && containTagsNot
            };
        }
    }
}

class DataManager {
    constructor(rules, state) {
        this.rules = rules;
        this.state = state;
        this.data = new Map();
        this.lazyImgLoader = new unsafeWindow.bhutils.LazyImgLoader((target) => !this.isFiltered(target));
        this.dataFilters = new DataFilter(rules, state).filters;
    }

    static filterDSLToRegex(str) {
        const toFullWord = w => `(^|\ )${w}($|\ )`;
        const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
        return unsafeWindow.bhutils.stringToWords(str_).map(expr => new RegExp(expr, 'i'));
    }

    isFiltered(el) {
        return el.className.includes('filtered');
    }

    applyFilters = (filters, offset = 0) => {
        const filtersToApply = Object.keys(filters)
            .filter(k => Object.hasOwn(this.dataFilters, k))
            .map(k => this.dataFilters[k]());

        if (filtersToApply.length === 0) return;

        let updates = [];
        let offset_counter = 1;
        for (const v of this.data.values()) {
            if (++offset_counter > offset) {
                for (const f of filtersToApply) {
                    const {tag, condition} = f(v);
                    updates.push(() => v.element.classList.toggle(tag, condition));
                }
            }
        }

        requestAnimationFrame(() => {
            updates.forEach(update => update());
        });
    }

    filterAll = (offset) => {
        const filters = Object.assign({}, ...Object.keys(this.dataFilters).map(f => ({ [f]: this.state[f] })));
        this.applyFilters(filters, offset);
    }

    handleLoadedHTML = (html, container, removeDuplicates = false, shouldLazify = true) => {
        const thumbs = this.rules.GET_THUMBS(html);
        const data_offset = this.data.size;

        for (const thumbElement of thumbs) {
            const url = this.rules.THUMB_URL(thumbElement);
            if (!url || this.data.has(url)) {
                if (removeDuplicates) thumbElement.remove();
                continue;
            }

            const { title, duration } = this.rules.THUMB_DATA(thumbElement);
            this.data.set(url, { element: thumbElement, duration, title });

            if (shouldLazify) {
                const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
                this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
            }

            const parent = container || this.rules.CONTAINER;
            if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
        }

        this.filterAll(data_offset);
    };
}