Редирект-кнопка для Шикимори, которая перенаправляет на Anime365
Mint
"use strict";
// ==UserScript==
// @name ShikiLinker
// @description Редирект-кнопка для Шикимори, которая перенаправляет на Anime365
// @description:en Redirect button for Shikimori that redirects to Anime 365
// @namespace https://shikimori.one/animes
// @include /^https?://shikimori\.o(?:ne|rg)/(.*)$/
// @connect smotret-anime.online
// @grant GM_xmlhttpRequest
// @icon https://www.google.com/s2/favicons?domain=shikimori.one
// @author Jogeer
// @license MIT
// @version 2.1.2
// @compatible chrome
// @contributionURL https://paypal.me/Jogeer
// @contributionAmount 5
// ==/UserScript==
const DEBUG = false;
const PAGEURL = new RegExp(/^https?:\/\/shikimori\.o(?:ne|rg)\/animes\/[A-z]?(\d*)-(.*)$/);
const A365URL = 'https://smotret-anime.online/';
const A365API = `${A365URL}api/`;
const SHIKIAPI = 'https://shikimori.one/api/';
const NYAASI = 'https://nyaa.si/?';
const DISTRIB = 'Erai-raws';
const PARENSSTYLES = "display:flex;flex-direction:row;flex-wrap:wrap;align-content:center;justify-content:center;align-items:center;margin-top:10px";
const CHILDSTYLES = "flex:1 1 auto;text-align:center;padding:5px;background:#18181b;color:white;margin: 0 10px";
const SPANSTYLES = "width:100%;text-align:center;";
const BASICLINKATTRS = [{ attribute: 'class', value: 'link-button' }, { attribute: 'target', value: '_balnk' }, { attribute: 'style', value: CHILDSTYLES }];
class ShikiLinker {
static async MakeRequest(url) {
return await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
headers: { "Content-type": "application/json" },
url: `${url}`,
onload: async (data) => {
data = await JSON.parse(data.response);
DEBUG ? console.log(`Request to ${url}`, data) : null;
resolve(data);
},
onerror: async (data) => {
DEBUG ? console.error(`Request to ${url}`, data) : null;
reject(null);
}
});
});
}
static ParseUserData() {
return JSON.parse(document.querySelector('body').getAttribute('data-user'));
}
static BuildElement(element) {
let attrs = '';
element.attributes.forEach((el) => {
let _val = '';
el.value ? _val = `=\"${el.value}\"` : null;
attrs += `${el.attribute}${_val} `;
});
return `<${element.tag} ${attrs}>${element.text}</${element.tag}>`;
}
static async AddDomParentContainer(toSelector) {
if (document.querySelector('#shikilinker-inject')) {
DEBUG ? console.log('Parent container already exist') : null;
return false;
}
else {
let documentDom = document.querySelector(toSelector);
documentDom.insertAdjacentHTML('beforeend', ShikiLinker.BuildElement({ tag: 'div', attributes: [{ attribute: 'class', value: 'watch-online' }, { attribute: 'id', value: 'shikilinker-inject' }, { attribute: 'style', value: PARENSSTYLES }], text: '' }));
DEBUG ? console.log('Parent container has been added') : null;
return true;
}
}
static async AddElement(element) {
let documentDom = document.querySelector('#shikilinker-inject');
DEBUG ? console.log('Add:', element, ' to:', documentDom) : null;
documentDom.insertAdjacentHTML('beforeend', ShikiLinker.BuildElement(element));
}
static async HaveNonWatchedEpisode(a365Data, shikiData) {
DEBUG ? console.log("API data:", a365Data, shikiData) : null;
if (!shikiData || !shikiData.episodes) {
shikiData = JSON.parse('{"status": "none", "episodes": 0}');
}
if (["completed", "dropped"].includes(shikiData.status) || shikiData.episodes >= a365Data.episodes.length) {
return false;
}
return true;
}
static async Execute() {
if (!await ShikiLinker.AddDomParentContainer('.c-info-right')) {
DEBUG ? console.log('Block already exist') : null;
return;
}
let matches = PAGEURL.exec(window.location.href);
let userData = await ShikiLinker.ParseUserData(); // await JSON.parse(document.querySelector('body').getAttribute('data-user'));
DEBUG ? console.log('PR done:', matches, userData) : null;
let a365Data = await ShikiLinker.MakeRequest(`${A365API}series?myAnimeListId=${matches[1]}`);
let shikiData = await ShikiLinker.MakeRequest(`${SHIKIAPI}v2/user_rates?user_id=${userData.id}&target_id=${matches[1]}&target_type=Anime`);
DEBUG ? console.log('Req done:', a365Data, shikiData) : null;
ShikiLinker.AddElement({ tag: 'a', attributes: [{ attribute: 'href', value: a365Data.data[0].url }].concat(BASICLINKATTRS), text: 'Anime 365' });
if (await ShikiLinker.HaveNonWatchedEpisode(a365Data.data[0], shikiData[0])) {
DEBUG ? console.log('Have nonwatched ep') : null;
try {
ShikiLinker.AddElement({ tag: 'a', attributes: [{ attribute: 'href', value: `${A365URL}episodes/${a365Data.data[0].episodes[shikiData[0].episodes].id}` }].concat(BASICLINKATTRS), text: `${shikiData[0].episodes + 1} ep` });
}
catch (error) {
null;
}
}
ShikiLinker.AddElement({ tag: 'a', attributes: [{ attribute: 'href', value: `${NYAASI}u=${DISTRIB}&q=${document.querySelector('meta[property="og:title"]').content}` }].concat(BASICLINKATTRS), text: 'Nyaa.si' });
ShikiLinker.AddElement({ tag: 'span', attributes: [{ attribute: 'style', value: SPANSTYLES }], text: 'ShikiLinker' });
}
}
function ready(func) {
//var document = document.documentElement;
document.addEventListener('turbolinks:load', func);
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
func();
}
else {
document.addEventListener('DOMContentLoaded', func);
}
}
ready(ShikiLinker.Execute);