// ==UserScript==
// @name shikiPlus
// @author chsa13
// @description script add viewer and playeer on shikimori
// @namespace http://shikimori.me/
// @version 1.7
// @match *://shikimori.org/*
// @match *://shikimori.one/*
// @match *://shikimori.me/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=shikimori.me
// @license MIT
// @copyright Copyright © 2024 chsa13. All rights reserved.
// ==/UserScript==
let RonobeLibLink = "https://ranobelib.me/ru/"
let MangaLibLink = "https://test-front.mangalib.me/ru/"
let AnimeLibLink = "https://anilib.me/ru/anime/"
let LibSocialApiLink = 'https://api.lib.social/api'
function launchFullScreen(element) {
if (element.requestFullScreen) {
element.requestFullScreen();
}
else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
}
else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
}
}
function ready(fn) {
document.addEventListener('page:load', fn);
document.addEventListener('turbolinks:load', fn);
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") fn();
else document.addEventListener('DOMContentLoaded', fn);
}
async function sleep(timeMs) {
await new Promise(resolve => setTimeout(resolve, timeMs));
}
async function GetResourceAsync(uri, config = {}) {
return await new Promise((resolve, reject) => {
$.ajax(Object.assign({
url: uri,
dataType: 'json',
async: true,
cache: false,
success: function(res) {
resolve(res);
},
error: function(xhr) {
reject(xhr);
}
}, config));
});
}
async function ranobelib(hrefs, type) {
let sets = document.createElement("div");
sets.style.cssText = `
margin-bottom: 10px;
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
`;
let sweatcher = document.createElement("div");
sweatcher.style.cssText = `
opacity: 1;
display: flex;
align-items: center;
font-size: 20px;
color: var(--color-text-primary, --font-main, #F8F8F2);
white-space: nowrap;
`;
let sweatcherText = document.createElement("span");
sweatcherText.textContent = "Выбрать версию:";
sweatcherText.style.cssText = `
margin-right: 10px;
color: var(--color-text-primary, --font-main, #112233);
`;
let styleTag = document.createElement('style');
styleTag.textContent = `
@media (max-width: 768px) {
.hide-on-mobile-text {
display: none !important;
}
}
`;
document.head.appendChild(styleTag);
sweatcherText.classList.add('hide-on-mobile-text');
sweatcher.appendChild(sweatcherText);
for (let i in hrefs) {
let btm = document.createElement("div");
btm.style.cssText = `
cursor: pointer;
margin-right: 10px;
border-radius: 6px;
justify-content: center;
align-items: center;
width: 35px;
height: 35px;
color: var(--color-text-primary, #F8F8F2);
background-color: var(--color-background-button, #414141);
display: flex;
font-size: 16px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
`;
btm.textContent = (String(Number(i) + 1));
sweatcher.appendChild(btm);
btm.addEventListener("click", async () => {
if (type == "manga") {
fr.src = MangaLibLink + hrefs[i] + "/read/v01/c01";
} else if (type == "ranobe") {
fr.src = RonobeLibLink + hrefs[i] + "/read/v01/c01";
}
});
// Анимация для сенсорного касания
btm.addEventListener("touchstart", () => {
btm.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
btm.style.color = "#FFF";
btm.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
btm.style.transform = "translateY(-2px)";
});
btm.addEventListener("touchend", async () => {
btm.style.backgroundColor = "var(--color-background-button, #414141)";
btm.style.color = "var(--color-text-primary, #F8F8F2)";
btm.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
btm.style.transform = "translateY(0)";
});
// Анимация при наведении мышкой
btm.addEventListener("mouseover", () => {
btm.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
btm.style.color = "#FFF";
btm.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
btm.style.transform = "translateY(-2px)";
});
btm.addEventListener("mouseout", () => {
btm.style.backgroundColor = "var(--color-background-button, #414141)";
btm.style.color = "var(--color-text-primary, #F8F8F2)";
btm.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
btm.style.transform = "translateY(0)";
});
}
if (hrefs.length >= 2) sets.appendChild(sweatcher);
var fr = document.createElement("iframe");
if (type == "manga") {
fr.src = MangaLibLink + hrefs[0] + "/read/v01/c01";
} else if (type == "ranobe") {
fr.src = RonobeLibLink + hrefs[0] + "/read/v01/c01";
}
fr.setAttribute('allowFullScreen', 'allowfullscreen');
fr.style.cssText = `
width: 100%;
height: unset;
aspect-ratio: 1.36;
min-height: 650px;
border: none;
`;
let blackdiv = document.createElement("div");
blackdiv.style.cssText = `
position: absolute;
background-color: black;
width: 100%;
height: unset;
aspect-ratio: 1.36;
min-height: 650px;
border: none;
`;
let e = document.createElement("div");
e.style.cssText = `
display: flex;
align-items: center;
justify-content: flex-end;
height: 40px;
`;
sets.appendChild(e);
let g = document.createElement("div");
g.style.cssText = `
border-radius: 6px;
text-align: center;
font-size: 18px;
padding: 0 20px;
color: var(--color-text-primary, #F8F8F2);
background-color: var(--color-background-button, #414141);
cursor: pointer;
transition: all 0.3s ease;
white-space: nowrap;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
`;
g.textContent = "Полноэкранный режим";
e.appendChild(g);
g.addEventListener("click", async () => {
g.style.backgroundColor = "var(--color-background-button, #414141)";
g.style.color = "var(--color-text-primary, #F8F8F2)";
g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
g.style.transform = "translateY(0)";
launchFullScreen(fr);
});
// Анимация для сенсорного касания
g.addEventListener("touchstart", () => {
g.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
g.style.color = "#FFF";
g.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
g.style.transform = "translateY(-2px)";
});
g.addEventListener("touchend", async () => {
g.style.backgroundColor = "var(--color-background-button, #414141)";
g.style.color = "var(--color-text-primary, #F8F8F2)";
g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
g.style.transform = "translateY(0)";
});
// Анимация при наведении мышкой
g.addEventListener("mouseover", () => {
g.style.backgroundColor = "var(--color-primary-hover, #5F9EA0)";
g.style.color = "#FFF";
g.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
g.style.transform = "translateY(-2px)";
});
g.addEventListener("mouseout", () => {
g.style.backgroundColor = "var(--color-background-button, #414141)";
g.style.color = "var(--color-text-primary, #F8F8F2)";
g.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
g.style.transform = "translateY(0)";
});
fr.onload = async function() {
blackdiv.remove();
};
let container = document.querySelector('.b-db_entry');
let aboutSection = container.querySelector('.c-about');
let descriptionSection = container.querySelector('.c-description');
let imageSection = container.querySelector('.c-image');
// Проверка на мобильную версию
if (window.innerWidth <= 768) {
if (imageSection) {
imageSection.appendChild(sets);
imageSection.appendChild(blackdiv);
imageSection.appendChild(fr);
}
} else if (aboutSection && descriptionSection) {
container.insertBefore(sets, descriptionSection);
container.insertBefore(blackdiv, descriptionSection);
container.insertBefore(fr, descriptionSection);
}
}
async function animelib(href) {
var fr = document.createElement("iframe");
fr.src = AnimeLibLink + href.split("?")[0] + "/watch";
fr.setAttribute('allowFullScreen', 'allowfullscreen');
fr.style.cssText = `
width: 100%;
height: unset;
aspect-ratio: 1.36;
min-height: 650px;
border: none;
`;
let blackdiv = document.createElement("div");
blackdiv.style.cssText = `
position: absolute;
background-color: black;
width: 100%;
height: unset;
aspect-ratio: 1.36;
min-height: 650px;
border: none;
`;
// Находим контейнер
let container = document.querySelector('.b-db_entry');
let descriptionSection = container.querySelector('.c-description');
// Проверяем, существует ли нужный элемент
if (descriptionSection) {
// Если это мобильное устройство
if (window.innerWidth <= 768) {
let cImageElement = container.querySelector('.c-image');
if (cImageElement) {
// Вставляем черный div и iframe после "c-image"
cImageElement.appendChild(blackdiv);
cImageElement.appendChild(fr);
}
} else {
// Вставляем черный div перед описанием (десктопная версия)
container.insertBefore(blackdiv, descriptionSection);
// Вставляем iframe перед описанием (десктопная версия)
container.insertBefore(fr, descriptionSection);
}
}
fr.onload = async function() {
blackdiv.remove();
};
}
async function addBtn() {
if (document.querySelector('.shikiPlus')) return
let lic = false
let btn = document.createElement("div")
btn.classList.add("shikiPlus")
let clickFunc = function() {
1 == 1
}
let href = ""
let type
if (location.href.includes("/animes/")) {
let id = document.querySelector('.b-user_rate').getAttribute('data-target_id')
let title = document.querySelector("meta[property='og:title']").getAttribute('content')
try {
title = title.split(" ")[0]
}
catch {
1 == 1
}
console.log(title)
let response = await GetResourceAsync(LibSocialApiLink + "/anime?q=" + title)
href = ""
console.log(response)
for (let i in response.data) {
if (id == response.data[i].shikimori_href.split("/")[4]) {
href = response.data[i].slug_url
}
}
clickFunc = animelib
console.log(href)
}
else if (location.href.includes("/mangas/")) {
type = "manga"
await a(type)
}
else if (location.href.includes("/ranobe/")) {
type = "ranobe"
await a(type)
}
async function a(type) {
let as = []
if (type =="ranobe") as = document.querySelectorAll(".ranobelib > a")
if (type =="manga") as = document.querySelectorAll(".mangalib > a")
href = []
for (let i in as) {
if (as[i].href) {
i = (as[i].href.split("?")[0].replace("https://ranobelib.me/", "").replace("https://mangalib.me/", "").replace("ru/", "").replace("book/", "").replace("ranobes/", "").replace("ranobe/", "").replace("manga/", "").replace("mangas/", ""))
console.log(i)
let response = await GetResourceAsync(LibSocialApiLink + "/manga/" + i)
lic = response.data.is_licensed
href.push(response.data.slug_url)
}
}
clickFunc = ranobelib
}
btn.style.cssText = `
border-radius: 6px;
opacity: 1;
text-align: center;
font-size: 18px;
width: 100%;
height: 40px;
background-color: var(--color-background-button, #414141); /* Фон кнопки */
color: var(--color-text-secondary, #E1E1E3); /* Цвет текста */
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease; /* Плавные переходы */
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* Добавлена легкая тень */
`;
btn.addEventListener("click", async () => {
btn.remove();
console.log(href);
document.querySelector('.c-description').style.cssText = `
margin-left:0;
`
clickFunc(href, type);
});
// Анимация для сенсорного касания
btn.addEventListener("touchstart", () => {
btn.style.backgroundColor = "var(--color-surface-hover, #5F9EA0)";
btn.style.color = "var(--color-text-primary, #F8F8F2)";
btn.style.transform = "translateY(-2px)";
btn.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)";
});
btn.addEventListener("touchend", async () => {
btn.style.backgroundColor = "var(--color-background-button, #414141)";
btn.style.color = "var(--color-text-secondary, #E1E1E3)";
btn.style.transform = "translateY(0)";
btn.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)";
});
// Анимация при наведении мышкой
btn.addEventListener("mouseover", () => {
btn.style.backgroundColor = "var(--color-surface-hover, #5F9EA0)"; /* Цвет при наведении */
btn.style.color = "var(--color-text-primary, #F8F8F2)"; /* Цвет текста при наведении */
btn.style.transform = "translateY(-2px)"; /* Легкий подъем */
btn.style.boxShadow = "0 4px 8px rgba(0, 0, 0, 0.3)"; /* Увеличение тени */
});
btn.addEventListener("mouseout", () => {
btn.style.backgroundColor = "var(--color-background-button, #414141)"; /* Возвращаем оригинальный цвет */
btn.style.color = "var(--color-text-secondary, #E1E1E3)";
btn.style.transform = "translateY(0)"; /* Возвращаем в исходное положение */
btn.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.2)"; /* Восстанавливаем исходную тень */
});
if (!type) btn.textContent = "Смотреть"
else btn.textContent = "Читать"
if (!lic && (href || href.length)) document.querySelectorAll('.c-image').forEach(e => e.appendChild(btn))
}
ready(addBtn)