BS Link Preview

Zeigt eine Cover- und Genres-Vorschau beim Hovern über BS-Serienlinks

当前为 2019-05-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         BS Link Preview
// @namespace    https://bs.to/
// @version      1.0.2
// @description  Zeigt eine Cover- und Genres-Vorschau beim Hovern über BS-Serienlinks
// @author       Asu_nyan
// @match        https://bs.to/
// @match        https://burningseries.co/
// @icon         https://bs.to/favicon.ico
// @require      https://greasyfork.org/scripts/375096-bs-library/code/BS_Library.js
// @grant        none
// ==/UserScript==
// jshint esversion: 9

const BS = window.BS;
const interval = 1000 * 10;
const url_preview_pairs = [];
const preview = document.createElement('div');
const image = document.createElement('img');
const genres = document.createElement('div');
const anchors = getAnchors();
const links = getLinks();
const width = 180;
const height = 266;

BS.Helper.InjectCSS(null, `
.genre {
display: inline-block;
font-size: 10pt;
margin-bottom: 4px;
padding: 1px 4px;
border-radius: 1em;
background-color: dodgerblue;
color: white;
}
`);

(function() {
    'use strict';
    let urls = links;
    let promises = urls.map(url => fetch(url).then(res => res.text()));
    Promise.all(promises).then(res => {
        res.forEach(processData);
        setup();
        loop();
    });
})();

function loop() {
    setInterval(() => {
        links.splice(0, links.length);
        const newAnchors = getAnchors(x => !x.hasAttribute('data-listener'));
        newAnchors.forEach(a => {
            anchors.push(a);
            const url = normalize(a.href);
            if(links.includes(url)) links.push(url);
        });
        setEvents();
        if(links.length) {
            let promises = links.map(url => fetch(url).then(res => res.text()));
            Promise.all(promises).then(res => {
                res.forEach(processData);
            });
        }
    }, interval);
}

function setup() {
    genres.style.margin = "4px";
    genres.style.textAlign = "center";
    image.style.width = width + "px";
    image.style.height = height + "px";
    image.style.margin = "0";
    preview.style.position = "absolute";
    preview.style.left = "0px";
    preview.style.top = "0px";
    preview.style.maxWidth = width + "px";
    preview.style.background = "#505050";
    preview.style.color = "black";
    preview.style.zIndex = "999";
    preview.style.pointerEvents = "none";
    preview.style.display = "none";
    setEvents();
    preview.appendChild(image);
    document.body.appendChild(preview);
}

function setEvents() {
    anchors.forEach(a => {
        a.setAttribute('data-listener', true);
        a.addEventListener('mouseenter', mEnter);
        a.addEventListener('mouseleave', () => {
            preview.style.display = "none";
        });
    });
}

function getLinks(prevUrls) {
    let links = getAnchors();
    anchors.forEach(a => a.removeAttribute('title'));
    let allUrls = links.map(link => normalize(link.href));
    let filteredUrls = [];
    allUrls.forEach(url => {
        if(prevUrls) {
            if(!prevUrls.includes(url)) prevUrls.push(url);
        } else {
            if(!filteredUrls.includes(url)) filteredUrls.push(url);
        }
    });
    return (prevUrls) ? prevUrls : filteredUrls;
}

function getAnchors(filter) {
    if(filter)
        return Array.from(document.querySelectorAll('a[href^="serie/"]'))
            .concat(Array.from(document.querySelectorAll('a[href^="https://bs.to/serie/"]')))
            .concat(Array.from(document.querySelectorAll('a[href^="https://burningseries.co/serie/"]')))
            .filter(filter);
    return Array.from(document.querySelectorAll('a[href^="serie/"]'))
        .concat(Array.from(document.querySelectorAll('a[href^="https://bs.to/serie/"]')))
        .concat(Array.from(document.querySelectorAll('a[href^="https://burningseries.co/serie/"]')));
}

function normalize(url) {
    if(url){
        let urlArr = url.split('/');
        if(urlArr.length > 4) {
            urlArr.splice(5, urlArr.length);
        }
        return urlArr.join('/');
    }
}

function processData(data) {
    let data_div = document.createElement('div');
    data_div.innerHTML = data;
    let url = data_div.querySelector('meta[property="og:url"').content;
    let genres = Array.from(data_div.querySelectorAll('span[data-t="genre"]')).map(e => e.textContent);
    let link = data_div.querySelector('img[alt="Cover"]').src;
    url_preview_pairs.push({url: url, cover: link, genres: genres});
}

function mEnter(e) {
    preview.style.display = "initial";
    let show = url_preview_pairs.filter(x => x.url == normalize(e.path[0].href));
    image.src = show[0].cover;
    genres.innerHTML = show[0].genres.map(x => `<span class="genre">${x}</span>`).join(' ');
    preview.appendChild(genres);
    let target_rect = e.target.getBoundingClientRect();
    mPos = { x : e.clientX, y : e.clientY };
    preview.style.left = (mPos.x - width/2) + 'px';
    preview.style.top  = (mPos.y > (window.innerHeight/2)) ? (target_rect.y + window.scrollY - (height + 75)) + 'px' : (target_rect.y + window.scrollY + 75) + 'px';
}