old.myshows.me

С 1 мая 2024 года отключают old.myshows.me. Под ручку с ChatGPT попытался починить нужные мне места.

Stan na 22-04-2024. Zobacz najnowsza wersja.

// ==UserScript==
// @name         old.myshows.me
// @namespace    http://tampermonkey.net/
// @version      2024-04-22
// @description  С 1 мая 2024 года отключают old.myshows.me. Под ручку с ChatGPT попытался починить нужные мне места.
// @             Желательно использовать вместе с внешним видом от другого энтузиаста: https://userstyles.world/style/15722/old-myshows-me (инструкцию ищите там же)
// @author       SanBest93
// @match        https://myshows.me/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=myshows.me
// @grant        none
// @license      MIT
// ==/UserScript==

'use strict';

const originalTitleIsNeeded = true; // Всегда выводить оригинальные названия на странице 'https://myshows.me/profile/next/'. Не надо — замените на false
const postfix = '1080'; // Текст после s01e01. Мне так удобнее на торрентах искать. Не надо — замените на ''

let myMap = new Map(); // Сюда будем складывать соответствие showId — titleOriginal
let changed = 0; // Для проверки количества внесённых изменений
let changeIsNeeded = true; // Так мне просто понятнее
let STYLE;

// Запоминаем userName
let userName;
const headerLogin = document.querySelector('div.HeaderLogin__username');
if (headerLogin) userName = headerLogin.textContent;

// Обработчик события загрузки всего DOM
window.addEventListener('load', onPageLoad());

// Функция, которая будет выполняться после загрузки всего DOM
function onPageLoad() {
    // Создаём новый экземпляр MutationObserver
    var observer = new MutationObserver(function(mutations) {
        // При каждом изменении DOM вызываем функцию checkPage
        checkPage();
    });
    // Настраиваем наблюдение за изменениями DOM
    observer.observe(document.body, {
        subtree: true,
        childList: true
    });
}

// Функция, которая будет выполняться при изменении DOM
function checkPage() {
    // Для /profile/next/ ---->
    // Проверяем, является ли текущий URL страницей 'https://myshows.me/profile/next/'
    if (!linksAreSimilar(window.location.href, 'https://myshows.me/profile/next/') && changeIsNeeded !== true) {
        changeIsNeeded = true;
        changed = 0;
    }
    if (linksAreSimilar(window.location.href, 'https://myshows.me/profile/next/') && changeIsNeeded === true) {
        // Не знаю, какими стандартными функциями получаются данные.
        if (originalTitleIsNeeded === true) {
            // Создаём свою карту данных
            createMap();
        }
        if (myMap.size > 0 || originalTitleIsNeeded === false) {
            fixProfileNext();
            fixWatchSoonElements();
        }
        changeIsNeeded = changed === 0;
    }
    // <---- Для /profile/next/

    // Для /username/ ---->
    if (linksAreSimilar(window.location.href, 'https://myshows.me/' + userName)) {
        fixProfileNumbers();
    }
    // <---- Для /username/

    // Меняем стили через CSS
    initStyle();
}

// Создание своей карты соответствия данных
function createMap() {
    // Получаем содержимое <script> и преобразуем его в объект JavaScript
    const scriptElement = document.getElementById('__NUXT_DATA__');
    if (!scriptElement) return;
    const dataString = scriptElement.textContent;
    const dataObject = JSON.parse(dataString);
    let showIDs; // Массив сериалов
    let iShowIDs; // Адрес массива сериалов
    // Получаем нужные данные из объекта
    if (dataObject.length > 0) {
        // Тут будут нужные данные, если изначально была открыта страница 'https://myshows.me/profile/next/'
        iShowIDs = findKeyInArray(dataObject, 'list', 30);
        if (!iShowIDs) {
            // Тут будут нужные данные, если изначально была открыта страница 'https://myshows.me/<имя профиля>'
            iShowIDs = findKeyInArray(dataObject, 'userShows', 30);
        }
        // Проверяем заполненность. Если пусто, то
        if (!iShowIDs) {
            // Перезагружаем страницу.
            // Тогда точно попадутся правильные данные в '__NUXT_DATA__'
            location.reload();
            return;
        }
        // Если нашли адрес, получаем список сериалов
        showIDs = dataObject[iShowIDs];
    }

    // Перебираем полученный массив сериалов, заполняем карту.
    // На всякий случай с попыткой
    if (showIDs && typeof showIDs.forEach === 'function') {
        showIDs.forEach(element => {
            try {
                const show = dataObject[element].show;
                myMap.set(dataObject[dataObject[show].id].toString(), dataObject[dataObject[show].titleOriginal]);
            } catch (error) {
                console.error('[скрипт old.myshows.me] Ошибка в createMap():', error);
            }
        });
    }
}

// Функция проверки элементов
function fixProfileNext() {
    const rows = document.querySelectorAll('.Row');
    // Перебираем все элементы страницы
    rows.forEach(row => {
        checkChild(row);
    });
}

// Рекурсивная функция проверки всех вложенных элементов
function checkChild(row) {
    row.childNodes.forEach(child => {
        if (child.className === 'WatchSoon-episode') {
            fixSeasonEpisode(child);
        } else if (child.className === 'WatchSoon-show' && originalTitleIsNeeded === true) {
            fixTitle(child);
        } else {
            checkChild(child);
        }
    });
}

// Замена "1 x 1" на "s01e01"
// Если указан постфикс, тоже добавить
function fixSeasonEpisode(episode) {
    if (episode.nodeType === 1 && episode.childNodes.length === 4) {
        const part0 = episode.childNodes[0];
        const part1 = episode.childNodes[1]; // Изначально ' x '
        const part2 = episode.childNodes[2];
        if (part1.textContent !== '') {
            part0.textContent = addPrefix(part0.textContent, 's');
            part1.textContent = '';
            part2.textContent = addPrefix(part2.textContent, 'e') + (postfix === '' ? '' : ' ' + postfix);
            changed++;
        }
    }
}

// Замена названия на оригинальное
function fixTitle(show) {
    if (myMap.size > 0) {
        const parts = show.pathname.split("/");
        const showId = parts[parts.length - 2];
        const titleOriginal = myMap.get(showId);
        if (titleOriginal && titleOriginal !== '') {
            show.textContent = titleOriginal;
            changed++;
        }
    }
}

// Добавление префикса S или E к номеру сезона или серии
function addPrefix(text, prefix) {
    if (!text.toLowerCase().startsWith(prefix)) {
        const num = +text;
        text = (num < 10 ? prefix + '0' : prefix) + text;
    }
    return text;
}

// Общая функция для поиска ключа в массиве данных
function findKeyInArray(data, key, N) {
    const end = N === undefined ? data.length : Math.min(N, data.length); // Количество первых
    let result;
    for (let i = 0; i < end; i++) {
        // Проверяем, является ли элемент объектом и содержит ли указанный ключ
        if (typeof data[i] === 'object' && !!data[i] && key in data[i]) {
            // Если да, выводим значение ключа и прерываем цикл
            result = data[i][key];
            break;
        }
    }
    return result;
}

// Смена чисел профиля с "1к" на "1 000"
function fixProfileNumbers() {
    // Выбираем все div с классом UserHeader__stats-value на странице
    const statsValues = document.querySelectorAll('div.UserHeader__stats-value');
    if (statsValues && typeof statsValues.forEach === 'function' && statsValues.lenght !== 0) {
        // Перебираем коллекцию элементов и меняем их содержимое
        statsValues.forEach(element => {
            element.textContent = element.title;
        });
    }
}

// Проверка, что ссылки одинаковые
function linksAreSimilar(link1, link2) {
    // Удаляем последний слеш, если он есть
    link1 = link1.endsWith('/') ? link1.slice(0, -1) : link1;
    link2 = link2.endsWith('/') ? link2.slice(0, -1) : link2;
    // Сравниваем ссылки
    return link1 === link2;
}

// Исправляем текст, который стал в несколько строк с последним обновлением сайта
function fixWatchSoonElements() {
    const watchSoonElements = document.querySelectorAll('.WatchSoon__title-wrapper');
    if (!watchSoonElements) return;
    watchSoonElements.forEach(element => {
        // Ищем нужные элементы
        const showLink = element.querySelector('.WatchSoon-show');
        const episodeLink = element.querySelector('.WatchSoon-episode');
        // Если найдены, копируем содержимое в новый элемент
        if (showLink && episodeLink) {
            const showText = showLink.textContent;
            const episodeText = episodeLink.textContent.replace(' - ', ' — ');
            const episodeNameParts = episodeText.split(' — ');
            const episodeInfo = episodeNameParts[0]; // Часть episodeText до первого ' — '
            const episodeName = episodeNameParts[1] || ''; // Часть episodeText после первого ' — '

            const newElement = document.createElement('div');
            newElement.innerHTML = `<a href="${showLink.href}" target="_blank">${showText}</a> — ${episodeInfo} — <a href="${episodeLink.href}" target="_blank">${episodeName}</a>`;
            newElement.classList.add('OldMyShowsClass');
            // (описание классов см. в initStyle())

            // Вставляем новый элемент перед старым
            element.parentNode.insertBefore(newElement, element.nextSibling);
         }
    });
}

// Внешний вид стилей попробуем менять через CSS
function initStyle() {
    // Получить существующий элемент <style>
    STYLE = document.querySelector('style');
    if (!STYLE) {
        // Создать новый элемент <style> и установить его содержимое
        STYLE = document.createElement('style');
        // Вставить новый элемент <style> в <head>
        document.head.appendChild(STYLE);
    }
    const statsRowColor = 'white';

    STYLE.textContent += /*CSS*/ `
.WatchSoon__title-wrapper {
    display: none;
}

.OldMyShowsClass {
    font-size: 14px;
}

.UserHeader__stats-row {
    text-shadow:
            -1px -1px 0 black,
             1px -1px 0 black,
            -1px  1px 0 black,
             1px  1px 0 black;
    color: ${statsRowColor};
}

.UserHeader__stats-title {
    color: ${statsRowColor}
}

`.replace(/;/g, '!important;');
}
长期地址
遇到问题?请前往 GitHub 提 Issues,或加Q群1031348184

赞助商

Fishcpy

广告

Rainyun

注册一下就行

Rainyun

一年攒够 12 元