Greasy Fork

nyaa.si/sukebei.nyaa.si helper

infinite scroll and image previews of torrents (more in description)

// ==UserScript==
// @name         nyaa.si/sukebei.nyaa.si helper
// @namespace    https://nyaa.si/
// @version      0.2.1
// @description  infinite scroll and image previews of torrents (more in description)
// @author       Mossshine
// @match        https://sukebei.nyaa.si/*
// @match        https://nyaa.si/*
// @grant        none
// ==/UserScript==



(function() {
    'use strict';

    const BASE_URL = `${window.location.protocol}//${window.location.hostname}`;
    const IMAGE_REGEXP = /http(.*jpg|.*png)/g;
    const NEW_LINES = /\]/g;

    $('body').prepend(`
<style>
    .preloader {
        display: inline-block;
        position: relative;
        width: auto;
        height: 10px;
    }
    .preloader:after {
        content: " ";
        display: block;
        border-radius: 50%;
        width: 0;
        height: 0;
        position: relative;
        top: -8px;
        left: 31px;
        box-sizing: border-box;
        border: 12px solid #fff;
        border-color: #fff transparent #fff transparent;
        animation: preloader 1.2s infinite;
    }
    .total-known-pages .preloader:after {
        left: 0px !important;
    }
    .preloader.error:after {
        border-color: #fb2b48 transparent #fb2b48 transparent;
    }
    @keyframes preloader {
        0% {
            transform: rotate(0);
            animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
        }
        50% {
            transform: rotate(900deg);
            animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
        }
        100% {
            transform: rotate(1800deg);
        }
    }

    .loaded {
        background: black !important;
    }
    .torrent-previews .image {
        height: 125px;
        width: auto;
        object-fit: contain;
        padding: 5px;
    }
    .torrent-previews::-webkit-scrollbar {
        width: 0;
        height: 0;
    }
    .torrent-previews {
        display: flex;
        overflow-x: scroll;
        scrollbar-width: none;
    }
    .paginator-status .out-of {
        display: block;
        border-bottom: 2px solid #afafaf;
        margin-bottom: 3px;
    }
    .paginator-status {
        z-index: 999999999;
        position: fixed;
        display: flex;
        flex-direction: column;
        font-size: 25px;
        text-align: center;
        padding: 10px;
        background: #0000007a;
        border-bottom-right-radius: 10px;
    }
</style>   
<div class="paginator-status" style="display: none;">
    <span class="actual-page">1</span>
    <span class="out-of"></span>
    <span class="total-known-pages">1</span>
</div> 
    `);

    function Utilities() {}

    Utilities.prototype = {
        constructor: Utilities,
        nextPage: function (uri) {
            if(uri.has('p')) {
                uri.set('p', (parseInt(uri.get('p')) + 1).toString())
            } else {
                uri.set('p', '2');
            }
            return uri;
        },
        currentPage: function (uri) {
            if(uri.has('p')) {
                return uri.get('p');
            } else {
                return 1;
            }
        }
    };

    const Utils = new Utilities();

    let uri = new URLSearchParams(window.location.search);

    let isLoadingNextPage = false;
    $(window).on('wheel', function () {
        if(isLoadingNextPage === true) {
            return;
        }
        if(($(window).scrollTop() + $(window).height()) === $(document).height()) {
            Utils.nextPage(uri);

            isLoadingNextPage = true;
            $('.total-known-pages').html(`<div class="preloader"></div>`);

            $.ajax({
                url: BASE_URL + '/?' + uri.toString(),
                type: "GET",
                success: function (rawHtml) {
                    isLoadingNextPage = false;
                    let table = $(rawHtml).find('.torrent-list');
                    $('.torrent-list').find('tbody').append(table.find('tbody').html());

                    let currentHighest = 0;
                    $(rawHtml).find('ul.pagination a').each(function () {
                        let page = parseInt($(this).html());
                        if(page > currentHighest) {
                            currentHighest = page;
                        }
                    })

                    $('.actual-page').html(Utils.currentPage(uri));
                    $('.total-known-pages').html(currentHighest);
                    bindPreviews();
                }
            })
        }
    });

    let currentHighest = 0;
    $('ul.pagination').find('a').each(function () {
        let page = parseInt($(this).html());
        if(page > currentHighest) {
            currentHighest = page;
        }
    })

    $('.actual-page').html(Utils.currentPage(uri));
    $('.total-known-pages').html(currentHighest);
    $('.paginator-status').css('display', 'flex');

    bindPreviews();
    function bindPreviews()
    {
        $(".torrent-list tr:not(.loaded)").off().on('mouseover',function (e) {
            if(e.shiftKey === false) {
                return;
            }
            let row = $(this);
            if(row.hasClass('loaded') || row.hasClass('loading')) {
                return;
            }

            let torrentUrl = row.find("td[colspan='2'] > a");
            if(torrentUrl.length === 0) {
                return;
            }
            row.addClass('loading');

            let category = row.find('td:first-child > a');

            $.ajax({
                url: BASE_URL + torrentUrl.attr('href'),
                type: "GET",
                beforeSend: function () {
                    let preloader = category.find('.preloader');
                    if(preloader.length === 0) {
                        category.find('img').css('display', 'none');
                        category.append(`<div class="preloader"></div>`);
                    } else {
                        preloader.removeClass('error');
                    }
                },
                statusCode: {
                    429: function () {
                        row.removeClass('loading');
                        let preloader = category.find('.preloader');
                        if(preloader.length !== 0) {
                            preloader.addClass('error');
                        }
                    }
                },
                error: function () {
                    row.removeClass('loading');
                    let preloader = category.find('.preloader');
                    if(preloader.length !== 0) {
                        preloader.addClass('error');
                    }
                },
                success: function (rawHtml) {
                    row.removeClass('loading');
                    if(row.hasClass('loaded')) {
                        return;
                    }
                    row.addClass('loaded');
                    let rawDescription = $(rawHtml).find('#torrent-description').html();

                    rawDescription = rawDescription.replace(NEW_LINES, "\n");

                    let m;
                    let images = [];

                    while ((m = IMAGE_REGEXP.exec(rawDescription)) !== null) {
                        if (m.index === IMAGE_REGEXP.lastIndex) {
                            IMAGE_REGEXP.lastIndex++;
                        }

                        m.forEach((match, groupIndex) => {
                            if(groupIndex === 0) {
                                images.push(`<img class="image" src="${match}">`);
                            }
                        });
                    }
                    category.find('.preloader').each(function () {
                        $(this).remove();
                    })
                    category.find('img').css('display', 'block');

                    if(images.length > 0) {
                        row.after(`<tr><td colspan="9"><div class="torrent-previews">${images.join('\n')}</div></td></tr>`);
                    }
                }
            })
        });
    }
})();