Greasy Fork

Improved Channel Select Menu for Kbin

Adds subscribed magazines and liked collections to the channel select menu.

目前为 2024-01-08 提交的版本。查看 最新版本

// ==UserScript==
// @name         Improved Channel Select Menu for Kbin
// @namespace    http://tampermonkey.net/
// @version      0.1.0
// @description  Adds subscribed magazines and liked collections to the channel select menu.
// @author       NeighborlyFedora
// @match        *://kbin.social/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=kbin.social
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @license      GPL-3.0-or-later
// ==/UserScript==

//Code partially based on Floating Subs List by raltsm4k (https://greasyfork.org/en/scripts/469121-floating-subs-list)

let user;
let subs = [];
let clls = [];
let subs_html = [];
let clls_html = [];
let fetch_tries = 3;

(function() {
    'use strict';

    user = document.querySelector('#header a.login').getAttribute('href');

    if(user === '/login') return;

    const channel_list = document.querySelector('#header li:has(a[title="Select a channel"]) .dropdown__menu');
    Object.assign(channel_list, {
        id: 'channel-list'
    });

    const refresher = Object.assign(document.createElement('button'), {
        id: 'refresher',
        title: 'Refresh list',
    });
    refresher.appendChild(Object.assign(document.createElement('i'), {
        className: 'fa-solid fa-rotate'
    }));
    channel_list.prepend(refresher);
    refresher.addEventListener('click', function(){
        localStorage.removeItem('icsm_' + user);
        empty();
        $('#refresher').find('i').addClass('fa-spin');
        fetch_subs(1);
    });

    $('<style>').text(
        `
        #header #channel-list {
            scroll-behavior: auto;
            width: 25rem;
            height: 25rem;
            overflow-x: hidden;
            overflow-y: scroll;
        }

        #header #channel-list h3 {
            border-bottom: var(--kbin-sidebar-header-border);
            color: var(--kbin-sidebar-header-text-color);
            font-size: .8rem;
            width: 95%;
            margin: 1rem 0 0 2.5%;
            text-transform: uppercase;
        }

        #header #channel-list #refresher {
            display: inline !important;
            position: absolute;
            background: none;
            border: 0;
            color: var(--kbin-meta-link-color);
            cursor: pointer;
            height: auto;
            width: auto;
            text-indent: 0;
            right: 2.5%;
            text-align: right;
            margin: 1rem 0 0 1rem;
            padding: 0 !important;
        }

        #header #channel-list #refresher:hover {
            color: var(--kbin-meta-link-hover-color);
        }

        #header #channel-list li {
            height: auto;
        }

        #header #channel-list #sub_item a:has(figure) {
            display: flex !important;
            justify-content: left;
        }

        #header #channel-list a {
            overflow-x: hidden;
            position: relative;
            padding: .35rem 1rem !important;
        }

        #header #channel-list #sub_item figure{
            float: left;
            margin-right: 0.25rem;
        }

        #header #channel-list #sub_item figure img{
            width: 1.25rem;
            height: 1.25rem;
            vertical-align: middle;
        }

        #header #channel-list::-webkit-scrollbar {
            width: 8px;
        }

        .rounded-edges #header #channel-list::-webkit-scrollbar-track {
            border-top-right-radius: var(--kbin-rounded-edges-radius);
            border-bottom-right-radius: var(--kbin-rounded-edges-radius);
        }

        .rounded-edges #header #channel-list::-webkit-scrollbar-thumb  {
            border-radius: var(--kbin-rounded-edges-radius);
        }


        #header #channel-list::-webkit-scrollbar-track {
            background: var(--kbin-bg);
            border-left: var(--kbin-section-border);
        }


        #header #channel-list::-webkit-scrollbar-thumb {
            background: var(--kbin-meta-link-color);
            border-left: var(--kbin-section-border);
            transition-duration: 0.4s;
        }
        #header #channel-list::-webkit-scrollbar-thumb:hover {
            background: var(--kbin-meta-link-hover-color);
        }
        `
    ).appendTo(document.head);
    empty();
    const cache = JSON.parse(localStorage.getItem('icsm_' + user));
    if (cache === null || Date.now() >= cache.expire) {
        $('#refresher').find('i').addClass('fa-spin');
        fetch_subs(1);
    }else{
        console.log('Fetching from cache....');
        cache.subs.forEach(function(cached_html){
           subs.push($(Object.assign(document.createElement('li'),{
               id: 'sub_item'
           })).html(cached_html))
        });

        cache.clls.forEach(function(cached_html){
           clls.push($(Object.assign(document.createElement('li'),{
               id: 'sub_item'
           })).html(cached_html))
        });
        complete();
    }

})();

function empty(){
    subs.forEach((sub) => { sub.remove();} );
    clls.forEach((cll) => { cll.remove();} );
    subs = [];
    subs_html = [];
    clls = [];
    clls_html = [];
}

function fetch_subs(page){
    $.get( window.location.origin + '/settings/subscriptions/magazines?p=' + page, function(data) {
        const $dom = $($.parseHTML(data));
        const $subs_list = $dom.find('#content .magazines ul');
        console.log('Fetching page ' + page + ' of subscriptions....');
        if (!$subs_list.length) {
            if (fetch_tries > 0) {
                console.log('Failed to fetch page ' + page + ' of subscriptions. Retrying....');
                fetch_tries--;
                fetch_subs(page);
            } else {
                console.log('Failed to fetch page ' + page + ' of subscriptions. Out of attempts.');
            }
        }else{
            fetch_tries = 3;
            const $new_subs = $subs_list.children('li');
            $new_subs.each(function() {
                $(this).prop('id', 'sub_item');

                const $link = $(this).find('a');

                const $icon = $(this).find('figure');

                $link.removeClass();
                if(window.location.href.includes('/m/'+$link.text())){
                   $link.addClass('active');
                }

                $link.prepend($icon);
                $(this).append($link);
                $(this).find('small').remove();
                $(this).find('div').remove();
                subs.push($(this));
                subs_html.push($(this).html());
            });
            const $pg = $dom.find('#content .pagination__item--next-page.pagination__item--disabled');

            if ($pg.length) {
                fetch_colls(1);
            } else {
                fetch_subs(page+1);
            }
        }
    });
}


function fetch_colls(page){
    $.get( window.location.origin + '/magazines/collections?p=' + page, function(data) {
        const $dom = $($.parseHTML(data));
        const $clls_list = $dom.find('#content .categories tbody');
        console.log('Fetching page ' + page + ' of collections....');
        if (!$clls_list.length) {
            if (fetch_tries > 0) {
                console.log('Failed to fetch page ' + page + ' of collections. Retrying...');
                fetch_tries--;
                fetch_colls(page);
            } else {
                console.log('Failed to fetch page ' + page + ' of collections. Out of attempts.');
            }
        }else{
            fetch_tries = 3;
            const $new_clls = $clls_list.children('tr:has(button.active)');
            $new_clls.each(function() {

                const $link = $(this).find('td:first-child a');

                $link.removeClass();
                const $li = $(document.createElement('li'));
                $li.prop('id', 'sub_item');
                $li.append($link);
                clls.push($li);
                clls_html.push($li.html());
            });
            const $pg = $dom.find('#content .pagination__item--next-page.pagination__item--disabled');
            if ($pg.length) {
                localStorage.setItem('icsm_' + user, JSON.stringify({subs: subs_html, clls: clls_html, expire: Date.now() + 15 * 60 * 1000}));
                complete();
            } else {
                fetch_colls(page+1);
            }
        }
    });
}



function complete(){

    console.log('Filling menu....');

    $('#refresher').find('i').removeClass('fa-spin');

    $('#channel-list').children('h3').remove();

    $('#channel-list').prepend($(Object.assign(document.createElement('h3'), {
        id: 'cl-header-feeds',
        textContent: 'Feeds'
    })));

    $('#channel-list').prepend($('#refresher'));

    $('#channel-list').append($(Object.assign(document.createElement('h3'), {
        id: 'cl-header-subs',
        textContent: 'Subscribed Magazines'
    })));

    subs.sort(function(a, b){
        return a.find('a').text().trim().toLowerCase().localeCompare(b.find('a').text().trim().toLowerCase());
    });

    subs.forEach(function(sub) {
        $('#channel-list').append(sub);
        const $link = sub.find('a')
        if( window.location.href.endsWith('/m/'+$link.text().trim()) || window.location.href.includes('/m/'+$link.text().trim()+'/') ){
            $link.addClass('active');
        }else{
            $link.removeClass('active');
        }
    })

    $('#channel-list').append($(Object.assign(document.createElement('h3'), {
        id: 'cl-header-clls',
        textContent: 'Liked Collections'
    })));

    clls.sort(function(a, b){
        return a.text().trim().toLowerCase().localeCompare(b.text().trim().toLowerCase());
    });

    clls.forEach(function(cll) {
        $('#channel-list').append(cll);
        const $link = cll.find('a')
        if( window.location.href.includes('/c/'+$link.text().trim()) || window.location.href.includes('/c/'+$link.text().trim()+'/') ){
            $link.addClass('active');
        }else{
            $link.removeClass('active');
        }
    });

    console.log('Done!');

}