F95zone marker

Marks F95Zone threads for future reference

Verzia zo dňa 17.04.2022. Pozri najnovšiu verziu.

// ==UserScript==
// @name         F95zone marker
// @namespace    http://tampermonkey.net/
// @version      0.1.3
// @description  Marks F95Zone threads for future reference
// @author       agreg
// @license      MIT
// @match        https://f95zone.to/*
// @icon         https://www.google.com/s2/favicons?domain=f95zone.to
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    const THREADS = /^(https:\/\/f95zone.to)?\/threads\//;
    const OP = '.message-threadStarterPost';
    const OP_ICONS = `${OP} header .message-attribution-opposite`;
    let urlId = s => (!THREADS.test(s) ? null : s.replace(THREADS, '').match(/^([^\/]+\.)?([0-9]+)/)[2]);
    let $find = (s, e=document) => e.querySelector(s);
    let $find_ = (s, e=document) => Array.from( e.querySelectorAll(s) );
    let $parent = (e, check=()=>true) => (check(e.parentNode) ? e.parentNode : $parent(e.parentNode, check));
    let $e = (tag, options={}, ...children) => {var e = Object.assign(document.createElement(tag), options);
                                                children.forEach(x => e.append(x));
                                                return e}
    let $updData = (id, e, data=GM_getValue(id), upd={}) => {if (data) {
        GM_setValue(id, Object.assign(data, upd));
        e.classList[data.fade ? 'add' : 'remove']('-marker-fade');
        e.classList[data.mark ? 'add' : 'remove']('-marker-mark');
        e.title = data.info || "";
    } else {
        GM_deleteValue(id);
        e.classList.remove('-marker-fade', '-marker-mark');
        e.title = "";
    }}

    GM_addStyle(`.-marker-unmarked {opacity: 0.5}   .-marker-marked {color: rgb(193, 88, 88)}
                 .-marker-fade:not(:hover) {opacity: 0.25}   .-marker-fade:hover {outline: 2px solid black}   .-marker-mark {outline: 2px solid grey}
                 .-marker-dialog {position: fixed;  top: 30%;  left: 30%;  width: 40%;  background: rgb(29, 31, 33);  border-radius: 5px;  z-index:1000}
                 .-marker-dialog > * {margin: 1em}  .-marker-dialog textarea {width: calc(100% - 2em)}
                 .-marker-dialog .-marker-row > * {margin-left: .5em;  margin-right: .5em}`);

    $find_(".structItem-title").forEach(e => {                     // forum, similar threads
        let _id = urlId(e.getAttribute('uix-data-href')||"");
        _id && $updData(_id, $parent(e, x => x.classList.contains('structItem--thread')));
    });

    if (location.pathname.startsWith('/search/')) {                // search results
        $find_(".contentRow-title a").forEach(e => {
            let _id = urlId(e.href||"");
            console.log(e.href, _id)
            _id && $updData(_id, $parent(e, x => /^li$/i.test(x.tagName)));
        });
    }

    if (['/latest', '/sam/latest_alpha'].some(s => location.pathname.startsWith(s))) { // latest updates
        new MutationObserver(mutations => mutations.forEach(m => Array.from(m.addedNodes).filter(e => e.tagName).forEach(node => {
            console.warn(node, node.children);
            $find_("a.resource-tile_link", node).forEach(e => {
                let _id = urlId(e.href||"");
                console.log(e.href, _id)
                _id && $updData(_id, e);
            });
        }))).observe(document.body, {subtree: true, childList: true});
    }

    if (location.pathname.startsWith('/threads/') && $find(OP)) {  // first page of a thread
        var id = urlId(location.href);
        var op = $find(OP);
        var icons = $find(OP_ICONS);
        var icon = $e('i', {className: "fas fa-star"})
        var data = GM_getValue(id);
        var _$updData = (upd={}) => {$updData(id, op, data, upd);
                                     icon.classList.add(`-marker-${data ? "" : "un"}marked`);
                                     icon.classList.remove(`-marker-${data ? "un" : ""}marked`)}
        let $deleteMark = () => {if (confirm("Delete mark?")) {
            $toggleEdit();
            data = null;
            _$updData();
        }}
        var edit = null;
        let $toggleEdit = () => {
            if (edit) {
                edit.remove();
                edit = null;
            } else {
                data = data || {};
                document.body.append(edit = $e('div', {className: '-marker-dialog'},
                                               $e('textarea', {placeholder: "Tooltip", value: data.info||"", oninput () {_$updData({info: this.value})}}),
                                               $e('div', {className: '-marker-row'},
                                                  $e('label', {},
                                                     $e('input', {type: 'checkbox', checked: data.fade, onchange () {_$updData({fade: this.checked})}}),
                                                     $e('span', {innerText: "Fade"})),
                                                  $e('label', {},
                                                     $e('input', {type: 'checkbox', checked: data.mark, onchange () {_$updData({mark: this.checked})}}),
                                                     $e('span', {innerText: "Mark"}))),
                                               $e('div', {className: '-marker-row'},
                                                  $e('button', {innerText: "OK", onclick: $toggleEdit}),
                                                  $e('button', {innerText: "Delete", onclick: $deleteMark}))));
            }
        }
        if ( $find_('a', icons).some(e => e.innerText == "#1") ) {
          _$updData();
          icons.insertBefore($e('li', {}, $e('a', {href: location.href, onclick () {$toggleEdit();  return false}}, icon)),
                             icons.firstChild);
        }
    }
})();