diff --git a/javascript/pages/player.js b/javascript/pages/player.js index e22af1f..d02ce04 100644 --- a/javascript/pages/player.js +++ b/javascript/pages/player.js @@ -40,6 +40,9 @@ export async function LoadEpisode(e) { */ async function LoadAnime(id, e) { const stream_file = await LoadM3U8(id, e); + if (typeof stream_file === "undefined") { + return SendAPI.switch(); + } LoadPlayer(stream_file); } diff --git a/javascript/pages/player/mod_api.js b/javascript/pages/player/mod_api.js index 7a9c414..e5b4788 100644 --- a/javascript/pages/player/mod_api.js +++ b/javascript/pages/player/mod_api.js @@ -115,5 +115,9 @@ export const SendAPI = { error: (val) => { ParentWindow.postMessage({ key: 'tunime_error', value: val }, "*"); + }, + + switch: () => { + ParentWindow.postMessage({ key: 'tunime_switch', value: true }, "*"); } } \ No newline at end of file diff --git a/javascript/pages/player/mod_stream.js b/javascript/pages/player/mod_stream.js index a632637..c4c88e5 100644 --- a/javascript/pages/player/mod_stream.js +++ b/javascript/pages/player/mod_stream.js @@ -71,6 +71,9 @@ export async function LoadM3U8Episode(id, e) { } function GenLink(streams) { + if(typeof streams === "boolean"){ + return; + } STREAMS = { 360: streams['360'], 480: streams['480'], 720: streams['720'] }; fixStreamUrls(STREAMS); if (AUTOQUALITY) { @@ -111,10 +114,10 @@ function loadStreamTunime(id, e, kodik_link = undefined) { } loadFirstSuccessfulImage(tunime_data.thumbinals) .then((successfulImage) => { - if (successfulImage !== null) { - Player.setAttribute('poster', successfulImage); - } else { + if (typeof successfulImage === "undefined") { Player.setAttribute('poster', "/images/preview-image.png"); + } else { + Player.setAttribute('poster', successfulImage); } }); }); @@ -135,6 +138,9 @@ function LoadImage(url) { } async function loadFirstSuccessfulImage(urls) { + if(typeof urls === "undefined"){ + return; + } for (let url of urls) { url = url.indexOf("http") != -1 ? url : "https:" + url; const result = await LoadImage(url); diff --git a/javascript/pages/watch.js b/javascript/pages/watch.js index 7fb4d46..a4de3c1 100644 --- a/javascript/pages/watch.js +++ b/javascript/pages/watch.js @@ -1,8 +1,7 @@ -import { Kodik } from "../modules/Kodik.js"; import { Main } from "../modules/ShikiUSR.js"; import { LoadScreen } from "./watch/mod_load.js"; import { CheckID, LoadAnime } from "./watch/mod_resource.js"; -import { Player } from "./watch/mod_player.js"; +import { IPlayer } from "./watch/mod_player.js"; import { AutoScrollEpisodes } from "./watch/mod_scrolling.js"; import { Functional } from "./watch/mod_ui.js"; import { DifferenceInData, SaveLData, SetDifferenceData, Synch, SynchLData } from "./watch/mod_sdata.js"; @@ -20,6 +19,8 @@ export let $CONTINUE = new URLSearchParams(window.location.search).get("continue //Наведение на плеер export const $SHOWPLAYER = new URLSearchParams(window.location.search).get("player"); +export const Player = IPlayer.Init({ standart: $PARAMETERS.player.standart }); + ClearParams(['continue', 'player']); export let $RULES = undefined; @@ -47,123 +48,118 @@ Main(async (e) => { SynchLData(res); }); - //Загрузка данных аниме плеера kodik - Kodik.Search({ shikimori_id: $ID }, (response) => { - Player().events.onalredy((e) => { - //Начинает загрузку плеера после получения синхронизированных данных - Synch.Init().On((data) => { - if (data) { - Player().loadAnime(data.kodik_episode, data.kodik_dub); - } else { - Player().update(); - } - AutoScrollEpisodes(); - }); - }); - - //Автоматически проскролит до выбраного эпизода - Player().events.onloaded(async (i) => { - if (i == 1) { - AutoScrollEpisodes(); - } - }); + //Автоматически проскролит до выбраного эпизода + Player.on('loaded', ({ count }) => { + if (count == 1) { + AutoScrollEpisodes(); + } + }); - Player().events.onerror((data) => { - console.log(`Eror Tunime Player: ${data}`); - //Убираем автомотический выбор плеера из за ошибки - $PARAMETERS.player.standart = false; - //Если ошибка Tunime плеера то переключаем на обычный плеер Kodik - Player().update(false); - }) - - //Выполняем сохранение аниме если выбирается озвучка только первого эпизода - Player().translation.events.onselected((id_translation, user) => { - let e = Player().episodes.selected_episode; - if (user && e == 1 && id_translation) { - SaveLData(e, id_translation); - } - }); + Player.CMessage.on('error', (data) => { + console.log(`Eror Tunime Player:`, data); + //Если ошибка Tunime плеера то переключаем на обычный плеер Kodik + Player.Switch(); + }) + + //Выполняем сохранение аниме если выбирается озвучка только первого эпизода + Player.CTranslation.on('selected', ({ id, user_handler }) => { + const episode = Player.CEpisodes.selected; + if (user_handler && episode == 1 && id) { + SaveLData(episode, id); + } + }); - //Событие отправки выбора озвучки первого просмотра - Player().events.onplayed((e) => { - const data = DifferenceInData(); - if (!data[0] && !data[1]) - return; - if (data[0] && !data[1]) { + //Событие отправки выбора озвучки первого просмотра + Player.CMessage.on('play', () => { + const data = DifferenceInData(); + if (!data[0] && !data[1]) + return; + if (data[0] && !data[1]) { + Tunime.OnActiv.Voice($ID, data[0].kodik_dub); + SetDifferenceData(data[0]); + } else if (data[0] && data[1]) { + if (data[0].kodik_dub != data[1].kodik_dub) { Tunime.OnActiv.Voice($ID, data[0].kodik_dub); SetDifferenceData(data[0]); - } else if (data[0] && data[1]) { - if (data[0].kodik_dub != data[1].kodik_dub) { - Tunime.OnActiv.Voice($ID, data[0].kodik_dub); - SetDifferenceData(data[0]); - } } - }); + } + }); - //Подписываемся на обработчик событий выбора эпизода - //Этот обработчик будет сохранять последние выбраное аниме аниме - Player().episodes.events.onclicked((e, d) => { - SaveLData(e, d); + //Подписываемся на обработчик событий выбора эпизода + //Этот обработчик будет сохранять последние выбраное аниме + Player.CEpisodes.on('selected', ({ episode, translation, user_handler }) => { + if (user_handler) { + SaveLData(episode, translation); //Добавляем истоию просмотра - History().add(false, 0, 0, e); - }); + History().add(false, 0, 0, episode); + } + }); - //Подписываемся на обработчик событий пауза плеера - Player().events.onpause((d) => { - History().add(true, d.time) - }); + //Подписываемся на обработчик событий пауза плеера + Player.CMessage.on('pause', ({ time }) => { + History().add(true, time) + }); - //Подписываемся на обрботчик событий - Player().events.onplayed((e) => { - const userRate = UserRate().Get(); - if (userRate != null) { - if (userRate.episodes > e || userRate.status == "completed" || Private.INCOGNITO) { - return; - } - UserRate().Controls.Episode(Player().episodes.selected_episode) + //Подписываемся на обрботчик событий + Player.CMessage.on('play', ({ time, duration }) => { + const userRate = UserRate().Get(); + if (userRate != null) { + if (userRate.episodes > Player.CEpisodes.selected || userRate.status == "completed" || Private.INCOGNITO) { + return; } - }); + UserRate().Controls.Episode(Player.CEpisodes.selected); + } + }); - Player().events.onplayed((e) => { - if ($CONTINUE != null && $CONTINUE != false) { - //Получаем историю спика продолжение просмотра - let history = History().get(); - //Находим ID елемента из истории - let id = history.findIndex((x) => { return x.id == $ID }); - - //Если найдено и совпадают текущии эпизоды - if (id != -1 && Player().episodes.selected_episode == history[id].episode) { - //Воспроизводим с остановившегося момента - Player().functional.control("seek", { seconds: history[id].duration }); - //Устанавливаем что продолжение было включено - $CONTINUE = false; - } + Player.CMessage.on('play', () => { + if ($CONTINUE != null && $CONTINUE != false) { + //Получаем историю спика продолжение просмотра + let history = History().get(); + //Находим ID елемента из истории + let id = history.findIndex((x) => { return x.id == $ID }); + + //Если найдено и совпадают текущии эпизоды + if (id != -1 && Player.CEpisodes.selected == history[id].episode) { + //Воспроизводим с остановившегося момента + Player.PControl.Exec("seek", { seconds: history[id].duration }) + //Устанавливаем что продолжение было включено + $CONTINUE = false; } - }); + } + }); - //Обработчик события следующего эпизода - Player().events.onnext((e) => { - if (e.episodes.episodes_count == e.episodes.selected_episode) return; - const next_episode = e.episodes.selected_episode + 1; - e.functional.control(e.functional.methods[10], { episode: next_episode }); - e.episodes.selected_episode = next_episode; - e.episodes.AnimateSelect(next_episode); - SaveLData(next_episode, e.translation.id); - History().add(false, 0, 0, next_episode); - }); + //Обработчик события следующего эпизода + Player.CMessage.on('next', (e) => { + if (Player.CEpisodes.count == Player.CEpisodes.selected) return; + const next_episode = Player.CEpisodes.selected + 1; + Player.PControl.Exec("set_episode", { episode: next_episode }); + Player.CEpisodes.Select(next_episode); + SaveLData(next_episode, Player.CTranslation.id); + History().add(false, 0, 0, next_episode); + }); - //Альтернативный полный экран видеоплеера - Player().events.onfullscreen((e) => { - if (e.full) { - $('.player').addClass('fullscreen'); - } else { - $('.player').removeClass('fullscreen'); - } - }); + //Альтернативный полный экран видеоплеера + Player.CMessage.on("fullscreen", ({ value }) => { + if (value.full) { + $('.player').addClass('fullscreen'); + } else { + $('.player').removeClass('fullscreen'); + } + }); - //Инициализируем плеер - Player().init(response.results); + //Переключение плеера через Tunime player + Player.CMessage.on("switch", () => { + Player.Switch(); + }) + + //Начинает загрузку плеера после получения синхронизированных данных + Synch.Init().On((data) => { + if (data) { + Player.Init(data); + } else { + Player.Init(); + } }); //Загружаем аниме diff --git a/javascript/pages/watch/mod_download.js b/javascript/pages/watch/mod_download.js index 5bd9810..ec68f6c 100644 --- a/javascript/pages/watch/mod_download.js +++ b/javascript/pages/watch/mod_download.js @@ -1,7 +1,7 @@ import { ScrollElementWithMouse, Sleep } from "../../modules/functions.js"; import { Tunime } from "../../modules/TunimeApi.js"; import { WindowManagement } from "../../modules/Windows.js"; -import { Player } from "./mod_player.js"; +import { Player } from "../watch.js"; import { Anime } from "./mod_resource.js"; import { UserRate } from "./mod_urate.js"; @@ -408,7 +408,7 @@ class Loading { return; this.#loaded = true; - const e = Player().episodes.last_episode; + const e = Player.CEpisodes.count; if (e !== undefined && e > 1) $('.wrapper-episodes-d').removeClass('hide'); @@ -420,7 +420,7 @@ class Loading { } this.Download.events.OnSelect.bind(this.Download)(); - this.Download.functions.Select(Player().episodes.selected_episode); + this.Download.functions.Select(Player.CEpisodes.selected); } } @@ -571,8 +571,7 @@ const Structure = { show: function () { $("body").addClass("loading"); this.download.Loaded.Load(); - const index = Player().data.findIndex(x => x.id == Player().data_id); - const data = Player().data[index]; + const data = Player.selected; this.download.SetData(data); this.download.Automation.Show(); }, @@ -583,7 +582,7 @@ const Structure = { }, verif: function () { - return Player().loaded; + return Player.loaded; }, anim: { diff --git a/javascript/pages/watch/mod_franchise.js b/javascript/pages/watch/mod_franchise.js index 3a8f79a..502ba94 100644 --- a/javascript/pages/watch/mod_franchise.js +++ b/javascript/pages/watch/mod_franchise.js @@ -2,8 +2,7 @@ import { Sleep } from "../../modules/functions.js"; import { Kodik } from "../../modules/Kodik.js"; import { GraphQl } from "../../modules/ShikiAPI.js"; import { User } from "../../modules/ShikiUSR.js"; -import { $ID } from "../watch.js"; -import { Player } from "./mod_player.js"; +import { $ID, Player } from "../watch.js"; let A_LOADED = false; let B_LOADED = false; @@ -57,7 +56,7 @@ function LoadAnimeFranchise() { export async function InitFranchiseVoices() { UpdateVoices(); - Player().translation.events.onselected((e) => { + Player.CTranslation.on("selected", () => { $('.container-l').show(); $(`.icon-info > .voice`).addClass('none'); B_LOADED = false; @@ -66,12 +65,12 @@ export async function InitFranchiseVoices() { } async function UpdateVoices() { - if (Franchises.length <= 0 || !Player().translation.id) { + if (Franchises.length <= 0 || !Player.CTranslation.id) { B_LOADED = true; return HideLoad(); } - const trans_id = Player().translation.id; + const trans_id = Player.CTranslation.id; const promises = []; for (let i = 0; i < Franchises.length; i++) { const id = Franchises[i]; diff --git a/javascript/pages/watch/mod_history.js b/javascript/pages/watch/mod_history.js index 057d178..bbd6d82 100644 --- a/javascript/pages/watch/mod_history.js +++ b/javascript/pages/watch/mod_history.js @@ -1,5 +1,4 @@ -import { $ID } from "../watch.js"; -import { Player } from "./mod_player.js"; +import { $ID, Player } from "../watch.js"; import { Private } from "./mod_private.js"; import { Screenshots } from "./mod_resource.js"; @@ -26,7 +25,7 @@ const _history = { * @param {Int} i - прибавка эпихода если необходимо (Для переклбчение следующего эпизода) * @param {Int} e - текущий эпизод */ - add(cnt = false, duration = 0, i = 0, e = Player().episodes.selected_episode) { + add(cnt = false, duration = 0, i = 0, e = Player.CEpisodes.selected) { if (!this.shikiData || Private.INCOGNITO) { return; } @@ -40,14 +39,13 @@ const _history = { } else { image = `${screenshots[0].original}`; } - const dub = Player().translation.name; + const dub = Player.CTranslation.name; const type = this.shikiData.kind == "movie" ? "Фильм" : this.shikiData.kind == "ova" ? "OVA" : this.shikiData.kind == "ona" ? "ONA" : "Аниме"; - const item = { id: $ID, continue: cnt, duration, - fullduration: Player().video_data.duration, + fullduration: Player.VData.duration, episode, name: russian, image, diff --git a/javascript/pages/watch/mod_player.js b/javascript/pages/watch/mod_player.js index da4b1d5..cb21764 100644 --- a/javascript/pages/watch/mod_player.js +++ b/javascript/pages/watch/mod_player.js @@ -1,575 +1,612 @@ +import { Kodik } from "../../modules/Kodik.js"; import { AutoScrollEpisodes } from "./mod_scrolling.js"; import { $ID } from "../watch.js"; +import { Franchises } from "./mod_franchise.js"; + +//Функция генерация HTML перевода +function _genVoice(id, title, episod, save = false) { + return `
+
+ ${title} + ${episod ? episod : 1} +
+
+ + +
+
`; +} + +let _player = undefined; + +const player_callbacks = { + inited: [], + loaded: [] +} + +const message_callabcks = { + pause: [], + play: [], + error: [], + next: [], + fullscreen: [], + switch: [] +} + +const translation_callbacks = { + selected: [], + loaded: [] +} + +const episodes_callbacks = { + selected: [], + load: [] +} + +const control_methods = { + "play": '', // Запуск плеера + "pause": '', // Пауза + "seek": '', // Перемотка на заданную точку. Время указывается в секундах + "volume": '', // Изменение громкости. Значение громкости может быть от 0 до 1 + "mute": '', // Выключение звука + "unmute": '', // Включение звука + "change_episode": '', // Переключение серии + "enter_pip": '', // Вход в режим "Картинка в картинке" + "exit_pip": '', // Выход из режима "Картинка в картинке" + "get_time": '', // Получение текущего времени + "set_episode": '' //Включение эпизода (только Tunime Player) +} + +class Episodes { + #callbacks = episodes_callbacks; + /** + * @param {Player} Player + */ + constructor(Player) { + this.Player = Player; -//Управление плеером аниме -const player = { - data: [], - loaded: false, //Загрузился ли плеер (нужно для его управления) - loaded_int: 0, // Количество раз загрузки - data_uri: undefined, //Ссылка на плеер kodik - data_id: undefined, - alredy: false, // Готов плеер (ссылки для загрузки) для загрузки - name: 'kodik', //Название запущеного плеера - - uri: function (url) { - this.data_uri = url; - }, - - translation: { - key: "save-translations", // <- Ключ localstorage - id: undefined, // <- Текущая выбранная озвучка аниме - name: NaN, // <- Текущие название озвучки - selected: false, // <- Выбранна ли озвучка - - saved: [], // <- Сохраненые озвучки id (Избранное) - - //События связанные с озвучками - events: { - selected: [], - - /** - * Событие выбора озвучки аниме программно и пользователем пользователем - * @param {Function} e - функция для вызова - */ - onselected: function (e) { - if (typeof e == "function" && e.length > 0) { - this.selected.push(e); - } - } - }, - - /** - * Инициализация управление переводами аниме - * @param {Object} data - данные с kodik - */ - init: function (data) { - if ($PARAMETERS.watch.dubanime) this.key = "save-translations-" + $ID; - this.saved = JSON.parse(localStorage.getItem(this.key)); - this.saved = this.saved ? this.saved : []; - - //Проверяем что доступны озвучки в аниме - if (data.length != 0) { - //Удаляем заглушку - $(".content-voices").empty(); - } - - for (let i = 0; i < data.length; i++) { - const element = data[i]; - const translation = element.translation; - let finded = false; + this.selected = 1; + this.count = 0; + } - //Ищем в сохраненый переводах - if (this.saved && this.saved.indexOf(translation.id) != -1) { - finded = true; - } + Init(element) { + //Устанавливаем количество эпизодов + this.count = element.last_episode; - $(".content-voices").append(_genVoice(translation.id, translation.title, element.last_episode, finded)); + $(".episodes > .value > .episode").remove(); - //Выбрать дефолт - if (!this.selected && finded) { - this.select(translation.id); - } - } + for (let i = 1; i < this.count + 1; i++) { + const html = `${i}EP`; + $(".episodes > .value").append(html); + } - if (!this.selected && data.length > 0) { - this.select(data[0].translation.id); - } + //Инициалзация функционала + this.#Functional(); - //Нажатие на перевод - $(".voice > .voice-content").click((e) => { - this.select($(e.currentTarget).data("id"), true); - }); + if (this.selected > this.count) { + this.selected = 1; + } - //Добавить в избранное - $(".voice > .voice-save").click((e) => { - this.favorites($(e.currentTarget).data("id")); - }); + this.#Animate({ episod: this.selected, event: () => { AutoScrollEpisodes(); } }) - //Функция генерация HTML перевода - function _genVoice(id, title, episod, save = false) { - return `
-
- ${title} - ${episod ? episod : 1} -
-
- - -
-
`; - } - }, - - /** - * Выберает озвучку аниме - * @param {Int} id - перевода - */ - select: function (id, user_handler = false) { - if (this.id == id || id === undefined) return; - // Проверяем на существование такго обьекта в DOM - const element = $(`.voice[data-id="${id}"]`)[0]; - const data = player.data.find((x) => x.translation.id == id); - - if (this.selected) { - $(`.voice[data-id="${this.id}"]`).removeClass("select"); - } + this.#Dispatch('selected', { episode: this.selected, translation: this.Player.CTranslation.id, user_handler: false }); + } - this.id = id; //Индентификатор озвучки - this.selected = true; - this.name = data.translation.title;//Название озвучки + Select(e) { + if (e > this.count) return; + this.selected = e; + this.#Animate({ episod: this.selected }); + } - $(".current-translation > span").text(data.translation.title); //Title translation - if (data.last_episode) { - $(".count-current-translation").text(data.last_episode); //Last episode translation - } else if (data) { - $(".count-current-translation").text('1'); - $("#episodes").addClass('hide'); - } + Revise() { + this.#Animate({ episod: this.selected, event: () => { AutoScrollEpisodes(); } }) + } - $(element).addClass("select"); + #Functional() { + $(`.episode[data-index]`).on("click", (e) => { + const target = e.currentTarget; + const episode = $(target).data("index"); - //Проверяем что выбранная озвучка в избранном - if (this.saved && this.saved.indexOf(id) != -1) { - $(".translations-wrapper > .button-stars").addClass("selected"); - } else { - $(".translations-wrapper > .button-stars").removeClass("selected"); - } + //Проверяем если эпизод не выбран то выбираем его + if (!this.selected || this.selected != episode) { + this.selected = episode; - player.selectedTranslation(this.id); - - //Событие выбора озвучки - this.events.selected.forEach((event) => - event(this.id, user_handler) - ); - }, - - /** - * Добавляет озвучку в избранное - * @param {Int} id - перевод - */ - favorites: function (id) { - const element = $(`.voice > .voice-save[data-id="${id}"]`); - if (this.saved && this.saved.indexOf(id) != -1) { - //Удаляем с избранных - const index = this.saved.indexOf(id); - this.saved.splice(index, 1); - - element.removeClass('select'); - //Если выбран текущий перевод - if (this.id == id) { - $(".translations-wrapper > .button-stars").removeClass("selected"); - } + this.#Animate({ episod: this.selected }); - } else { - //Добавляем в избранное - this.saved.push(id); - element.addClass('select'); - //Если выбран текущий перевод - if (this.id == id) { - $(".translations-wrapper > .button-stars").addClass("selected"); - } + this.#Dispatch('selected', { episode, translation: this.Player.CTranslation.id, user_handler: true }); } + }); + } - //Сохраняем избранное - localStorage.setItem(this.key, JSON.stringify(this.saved)); - }, - }, - - episodes: { - episodes_count: 0, - last_episode: 0, - selected_episode: 1, - - events: { - clicked: [], - load: [], + #el = undefined; - onclicked: function (e) { - if (typeof e == "function" && e.length > 0) { - this.clicked.push(e); + /** + * Выполняет анимацию выбора эпизода + * @param {Object} params - Параметры для анимации + * @param {number} [params.episod=1] - Номер выбранного эпизода (по умолчанию 1) + * @param {Event} params.event - Событие, происходящее после выполнения анимации + * @param {Event} params.update - Событие для обновления данных анимации (передается текущая анимация) + * @returns {void} + */ + #Animate({ episod = 1, event, update } = {}) { + const element = $(".episodes > .value > .episode")[episod - 1]; + if (!element) { + return; + } + if (this.#el) { + anime({ + targets: this.#el, + color: "#555657", + easing: "easeOutElastic(1, 1)", + }); + } + this.#el = element; + const left = $(element).position().left; + const top = $(element).position().top + $(".episodes > .value").scrollTop(); + anime({ + targets: ".sel", + top: top, + easing: "easeOutElastic(1, 1)", + }); + anime({ + targets: ".sel", + left: left, + complete: function (anim) { + if (event) { + event(); } }, - - onload: function (e) { - if (typeof e == "function" && e.length > 0) { - this.load.push(e); + update: function (anim) { + if (update) { + update(anim); } }, - }, - - ShowEpisodes: function () { - AddEpisodes(this.last_episode); + easing: "easeOutElastic(1, 1)", + }); + anime({ + targets: element, + color: "#020202", + easing: "easeOutElastic(1, 1)", + }); + } - function AddEpisodes(i = 1) { - $(".episodes > .value > .episode").remove(); + /** + * Подписка на событие + * @param {keyof typeof episodes_callbacks} event - Название события (ключ из player_callbacks) + * @param {*} callback - Функция-обработчик для события + * @returns {void} + */ + on(event, callback) { + if (typeof callback !== "function") return; + if (this.#callbacks[event] === undefined) { + this.#callbacks[event] = []; + } + this.#callbacks[event].push(callback); + } - for (let index = 1; index < i + 1; index++) { - const html = `${index}EP`; - $(".episodes > .value").append(html); - } - Init(); //Инициализация функционала - //При инициализации проверяем выбраный эпизод и если эпизод выше возможного то изменяем на 1ый эпизод - if (player.episodes.selected_episode > player.episodes.last_episode) { - player.episodes.selected_episode = 1; - } - //Анимируем выбор первого эпизода автоматически - player.episodes.AnimateSelect(player.episodes.selected_episode, () => { AutoScrollEpisodes(); }); - //Даем плееру задачу обновить свои данные - player.update(); - //Вызываем событие обновление/изменение эпизодв - player.episodes.events.load.forEach((event) => - event(player.episodes.episodes_count) - ); - } + /** + * Вызов события + * @param {keyof typeof episodes_callbacks} event - Название события (ключ из player_callbacks) + * @param {object} data - Данные обратного вызова + * @returns {void} + */ + #Dispatch(event, data) { + if (this.#callbacks[event] === undefined) return; + this.#callbacks[event].forEach(callback => callback(data)); + } +} + +class Translation { + #callbacks = translation_callbacks; + /** + * @param {Player} Player + */ + constructor(Player) { + this.Player = Player; - /** - * Инициадизирует функционал кнопок епизодов - */ - function Init() { - $(`.episode[data-index]`).on("click", function (e) { - const target = e.currentTarget; - let episode = $(target).data("index"); //Епизод - //Проверяем если эпизод не выбран, выбираем его, делаем анимацию выбора, изменяем плеер - if ( - !player.episodes.selected_episode || - player.episodes.selected_episode != episode - ) { - //Вызываем подписанные события - player.episodes.events.clicked.forEach((event) => - event(episode, player.translation.id) - ); - //Выбираем эпизод - player.episodes.selected_episode = episode; - //Анимируем выбор эпизода - player.episodes.AnimateSelect(episode); - //Указываем плееру что были обновленны данные - player.update(); - } - }); - } - }, - - /** - * Делает анимацию выбора эпизода - * @param {Int} i - выбранный епизод - * @param {Event} e - событие после выполнение анимации - * @param {Event} u - событие обновление данных анимции - передается текущая анимация anime - * @returns - */ - AnimateSelect: function (i = 1, e, u) { - const element = $(".episodes > .value > .episode")[i - 1]; - if (!element) { - return; - } - if (this.selected) { - anime({ - targets: this.selected, - color: "#555657", - easing: "easeOutElastic(1, 1)", - }); - } - this.selected = element; - const left = $(element).position().left; - const top = $(element).position().top + $(".episodes > .value").scrollTop(); - anime({ - targets: ".sel", - top: top, - easing: "easeOutElastic(1, 1)", - }); - anime({ - targets: ".sel", - left: left, - complete: function (anim) { - if (e) { - e(); - } - }, - update: function (anim) { - if (u) { - u(anim); - } - }, - easing: "easeOutElastic(1, 1)", - }); - anime({ - targets: element, - color: "#020202", - easing: "easeOutElastic(1, 1)", - }); - }, - }, - - events: { - loaded: [], - paused: [], - played: [], - error: [], - next: [], - fullscreen: [], - alredy: [], - - /** - * Подписывается на обработчик загрузки плеера - * @param {Function} e - Событие которое будет вызвано - */ - onloaded: function (e) { - if (typeof e == "function" && e.length > 0) { - this.loaded.push(e); - } - }, + this.lskey = "save-translations"; + this.saved = [] //Сохранненые ID озвучек (Избранное) + this.selected = false; //Выбрана ли озвучка + this.id = undefined; //ID Выбранной озвучки + this.name = undefined; // Название выбранной озвучки + } - onpause: function (e) { - if (typeof e == "function" && e.length > 0) { - this.paused.push(e); + /** + * Инициализация озвучек + * @param {[{translation:{id:number, title:string},last_episode:number}]} data + */ + Init(data, id) { + if ($PARAMETERS.watch.dubanime) this.lskey = "save-translations-" + $ID; + this.saved = JSON.parse(localStorage.getItem(this.lskey)) || []; + + if ($PARAMETERS.watch.dubanime) { + for (let i = 0; i < Franchises.length; i++) { + const fid = Franchises[i]; + this.saved = this.saved.concat(JSON.parse(localStorage.getItem(`save-translations-${fid}`)) || []) } - }, + } - onplayed: function (e) { - if (typeof e == "function" && e.length > 0) { - this.played.push(e); - } - }, + if (data.length != 0) { + //Удалить заглушку + $(".content-voices").empty(); + } - onerror: function (e) { - if (typeof e == "function" && e.length > 0) { - this.error.push(e); - } - }, + for (let i = 0; i < data.length; i++) { + const element = data[i]; + const translation = element.translation; + let finded = false; - onnext: function (e) { - if (typeof e == "function" && e.length > 0) { - this.next.push(e); + if (this.saved && this.saved.indexOf(translation.id) != -1) { + finded = true; } - }, - onfullscreen: function (e) { - if (typeof e == "function" && e.length > 0) { - this.fullscreen.push(e); - } - }, + $(".content-voices").append(_genVoice(translation.id, translation.title, element.last_episode, finded)); - onalredy: function (e) { - if (typeof e == "function" && e.length > 0) { - this.alredy.push(e); + if (!this.selected && finded && id === undefined) { + this.Select({ id: translation.id }); } } - }, - - functional: { - methods: [ - "play", // Запуск плеера - "pause", // Пауза - "seek", // Перемотка на заданную точку. Время указывается в секундах - "volume", // Изменение громкости. Значение громкости может быть от 0 до 1 - "mute", // Выключение звука - "unmute", // Включение звука - "change_episode", // Переключение серии - "enter_pip", // Вход в режим "Картинка в картинке" - "exit_pip", // Выход из режима "Картинка в картинке" - "get_time", // Получение текущего времени - "set_episode" //Включение эпизода (только Tunime Player) - ], - - /** - * Функция для вызова управления плеером - * @param {String} method - метод функции - * @param {Object} data - данныне для отправки - */ - control: function (method = this.methods[0], data = {}) { - if (!player.loaded) { - return; - } - - let value = Object.assign({ method }, data); - document.querySelector("#kodik-player").contentWindow.postMessage({ key: "kodik_player_api", value: value }, '*'); + if (!this.selected && data.length > 0 && id === undefined) { + this.Select({ id: data[0].translation.id }); + } else if (!this.selected && data.length > 0 && id) { + this.Select({ id }); } - }, - video_data: { - duration: 0, //Продолжительность эпизода - time: 0, //Текущее время просмотра - }, + //Нажатие на перевод + $(".voice > .voice-content").click((e) => { + this.Select({ id: $(e.currentTarget).data("id"), user_handler: true }); + }); - /** - * Вабрана озвучка аниме - * * @param {Int} id - перевод - */ - selectedTranslation: function (id) { - //Id текущего елемента перевода - const idData = this.data.findIndex((x) => x.translation.id == id); + //Добавить в избранное + $(".voice > .voice-save").click((e) => { + this.Favorites($(e.currentTarget).data("id")); + }); - //Елемент который выбрал пользователь - const element = this.data[idData]; + this.#Dispatch('loaded', this.Player); + } - //Устанавливаем url адрес плеера - this.uri(element.link); - this.data_id = element.id; + Favorites(id) { + const element = $(`.voice > .voice-save[data-id="${id}"]`); + if (this.saved && this.saved.indexOf(id) != -1) { + //Удаляем с избранных + const index = this.saved.indexOf(id); + this.saved.splice(index, 1); - //Устанавливаем количество еаизодов - this.episodes.episodes_count = element.episodes_count; - this.episodes.last_episode = element.last_episode; + element.removeClass('select'); + //Если выбран текущий перевод + if (this.id == id) { + $(".translations-wrapper > .button-stars").removeClass("selected"); + } - //Отображаем епизоды пользователю - this.episodes.ShowEpisodes(); - }, + } else { + //Добавляем в избранное + this.saved.push(id); + element.addClass('select'); + //Если выбран текущий перевод + if (this.id == id) { + $(".translations-wrapper > .button-stars").addClass("selected"); + } + } + + //Сохраняем избранное + localStorage.setItem(this.lskey, JSON.stringify(this.saved)); + } /** - * Событие изменение данных плеера + * Выберает озвучку для аниме + * @param {{id: number, user_handler:boolean}} param0 */ - update: function (standart = $PARAMETERS.player.standart) { - //Выбранный эпизод - const episode = this.episodes.selected_episode; + Select({ id, user_handler = false }) { + if (this.id == id || id === undefined) return; - //Проверяем эпизод на наличие данных - if (!episode) { - console.log("Ошибка с выбранным епизодом"); - return; - } + const element = $(`.voice[data-id="${id}"]`)[0]; + const data = this.Player.results.find(x => x.translation.id == id); - //Проверяем на наличие ссылки на плеер - if (!this.data_uri) { - console.log("Ошибка с ссылкой на плеер", this.data_uri); - return; + if (!data) return console.log('Translation not found'); + + if (this.selected) { + $(`.voice[data-id="${this.id}"]`).removeClass("select"); } - //Указываем что плеер не загружен - this.loaded = false; + this.id = id; //Индентификатор озвучки + this.selected = true; + this.name = data.translation.title; //Название озвучки - //Изменяем ссылку на плеер (не используем тег src для того чтобы не созранять его в истори браузера) + $(".current-translation > span").text(data.translation.title); //Название озвучки - let url = this.data_uri + "?hide_selectors=true" + "&episode=" + episode - this.name = "kodik"; - if (standart) { - url = `player.html?id=${this.data_id}&e=${episode}`; - this.name = "tunime"; + if (data.last_episode) { + $(".count-current-translation").text(data.last_episode); //Last episode translation + } else if (data) { + $(".count-current-translation").text('1'); + $("#episodes").addClass('hide'); } - if (!this.alredy) { - this.alredy = true; - this.events.alredy.forEach((event) => event(this.alredy)); + $(element).addClass("select"); + + if (this.saved && this.saved.indexOf(id) != -1) { + $(".translations-wrapper > .button-stars").addClass("selected"); } else { - document.querySelector("#kodik-player").contentWindow.location.replace(url); + $(".translations-wrapper > .button-stars").removeClass("selected"); } - //Вызываем функцию которая будет отслеживать загрузился ли плеер и добавлять количество какой раз загрузился плеер - this.loading(); - }, + this.#Dispatch('selected', { id: this.id, user_handler }); + } /** - * Функция ожидание загрузки плеера + * Подписка на событие + * @param {keyof typeof translation_callbacks} event - Название события (ключ из player_callbacks) + * @param {*} callback - Функция-обработчик для события + * @returns {void} */ - loading: function () { - //Находим елемент на страницe - const element = document.querySelector("#kodik-player"); - if (element) { - let interval; - - interval = setInterval(() => { - try { - if (element.contentWindow.document) { - if (element.contentWindow.window.location.href.indexOf("player") != -1) { - //Очищаем интервао - clearInterval(interval); - - //Устанавливаем значения - this.loaded = true; - this.loaded_int++; - - //Вызываем событие - this.events.loaded.forEach((event) => event(this.loaded_int)); - } - } - //Когда плеер загрузится будет ошибка CORS - } catch (error) { - //Очищаем интервао - clearInterval(interval); + on(event, callback) { + if (typeof callback !== "function") return; + if (this.#callbacks[event] === undefined) { + this.#callbacks[event] = []; + } + this.#callbacks[event].push(callback); + } - //Устанавливаем значения - this.loaded = true; - this.loaded_int++; - //Вызываем событие - this.events.loaded.forEach((event) => event(this.loaded_int)); - } - }, 100); - } - }, + /** + * Вызов события + * @param {keyof typeof translation_callbacks} event - Название события (ключ из player_callbacks) + * @param {object} data - Данные обратного вызова + * @returns {void} + */ + #Dispatch(event, data) { + if (this.#callbacks[event] === undefined) return; + this.#callbacks[event].forEach(callback => callback(data)); + } +} +class Control { /** - * - * @param {Int} e - Эпизод аниме - * @param {Int} d - ID дубляжа + * @param {Player} Player */ - loadAnime: function (e, d) { - this.episodes.selected_episode = e; - this.translation.select(d); - this.episodes.AnimateSelect(e); - this.update(); - }, + constructor(Player) { + this.Player = Player; + } - saveAnime: function () { }, + /** + * Укправление плеером + * @param {keyof typeof control_methods} method - Название события (ключ из player_callbacks) + * @param {object} data - Данные для отправки + * @returns {void} + */ + Exec(method, data = {}) { + if (!this.Player.loaded) { + return; + } + + let value = Object.assign({ method }, data); + + document.querySelector("#kodik-player").contentWindow.postMessage({ key: "kodik_player_api", value: value }, '*'); + } +} - playerMessage: function (message) { +class Message { + #callbacks = message_callabcks; + + /** + * @param {Player} Player + */ + constructor(Player) { + this.Player = Player; + if (window.addEventListener) { + window.addEventListener("message", this.#Listener.bind(this)); + } else { + window.attachEvent("onmessage", this.#Listener.bind(this)); + } + } + + #Listener(message) { //Продолжительность всего видео if (message.data.key == "kodik_player_duration_update") { - player.video_data.duration = message.data.value; + this.Player.VData.duration = message.data.value; } //Текущее время видео if (message.data.key == "kodik_player_time_update") { - player.video_data.time = message.data.value; + this.Player.VData.time = message.data.value; } //Статус плеера изменен на паузу if (message.data.key == "kodik_player_pause") { - //Вызываем событие - player.events.paused.forEach((event) => event(player.video_data)); + this.#Dispatch('pause', this.Player.VData); } //Статус плеера изменен на воспроизведение if (message.data.key == "kodik_player_play") { - //Вызываем событие - player.events.played.forEach((event) => event(player.video_data)); + this.#Dispatch('play', this.Player.VData); } //Статус плеера tunime ошибка if (message.data.key == "tunime_error") { - //Вызываем событие - player.events.error.forEach((event) => event(message.data.value)); + this.#Dispatch('error', { value: message.data.value }); } //Статус плеера переключение эпизода if (message.data.key == "tunime_next") { - player.events.next.forEach((event) => event(player)); + this.#Dispatch('next', this.Player); } + // Альтернативный полный экран if (message.data.key == "tunime_fullscreen") { - player.events.fullscreen.forEach((event) => event(message.data.value)); + this.#Dispatch('fullscreen', { value: message.data.value }); } - }, + + // Переключение плеера + if (message.data.key == "tunime_switch") { + this.#Dispatch('switch', { value: message.data.value }); + } + } /** - * Инизиализирует обьект на правильную работу - * @param {Object} data - ответ с ресурса kodikDB + * Подписка на событие + * @param {keyof typeof message_callabcks} event - Название события (ключ из player_callbacks) + * @param {*} callback - Функция-обработчик для события + * @returns {void} */ - init: function (data) { - this.data = data; - this.translation.init(this.data); + on(event, callback) { + if (typeof callback !== "function") return; + if (this.#callbacks[event] === undefined) { + this.#callbacks[event] = []; + } + this.#callbacks[event].push(callback); + } - //Прослушиваем данные которые присылает нам плеер kodik - if (window.addEventListener) { - window.addEventListener("message", this.playerMessage); - } else { - window.attachEvent("onmessage", this.playerMessage); + + /** + * Вызов события + * @param {keyof typeof message_callabcks} event - Название события (ключ из player_callbacks) + * @param {object} data - Данные обратного вызова + * @returns {void} + */ + #Dispatch(event, data) { + if (this.#callbacks[event] === undefined) return; + this.#callbacks[event].forEach(callback => callback(data)); + } +} + +class Player { + #callbacks = player_callbacks; + + constructor({ standart = false } = {}) { + this.results = []; + + this.VData = { + duration: 0, //Продолжительность эпизода + time: 0 //Текущее время просмотра } - //Отслеживаем изменение ориентации экрана для правильного отображения выбраного эпизода - window.addEventListener("orientationchange", function () { - player.episodes.AnimateSelect(player.episodes.selected_episode, () => { AutoScrollEpisodes() }); + this.CMessage = new Message(this); + this.PControl = new Control(this); + this.CTranslation = new Translation(this); + this.CEpisodes = new Episodes(this); + + this.selected = undefined; + this.loaded = false; + this.name = standart ? "tunime" : "kodik"; + + this.CTranslation.on('selected', ({ id }) => { + // Порядковый номервыбраного елемента (озвучки) + const idData = this.results.findIndex(x => x.translation.id == id); + + // Выбранный елемент текущей озвучки + this.selected = this.results[idData]; + this.CEpisodes.Init(this.selected); + }); + + this.CEpisodes.on('selected', this.#Update.bind(this)); + } + + Init({ kodik_episode = undefined, kodik_dub = undefined } = {}) { + return new Promise((resolve) => { + Kodik.Search({ shikimori_id: $ID }, (response) => { + if (kodik_episode) { + this.CEpisodes.selected = kodik_episode; + } + this.results = response.results; + this.CTranslation.Init(this.results, kodik_dub); + this.#Dispatch('inited', this.results); + return resolve(this.results); + }); }); - }, -}; + } + + Switch() { + this.name = this.name === "kodik" ? "tunime" : "kodik"; + this.#Update({ episode: this.CEpisodes.selected }); + } + + #Update({ episode }) { + const uri = this.selected.link; + this.loaded = false; + let url = `${uri}?hide_selectors=true&episode=${episode}`; + if (this.name === "tunime") { + url = `player.html?id=${this.selected.id}&e=${episode}` + } + document.querySelector("#kodik-player").contentWindow.location.replace(url); + this.#Loading(); + } + + #loadCount = 0; + + #Loading() { + //Находим елемент на страницe + const element = document.querySelector("#kodik-player"); + let interval = setInterval(() => { + try { + if (element.contentWindow.document) { + if (element.contentWindow.window.location.href.indexOf("player") != -1) { + //Очищаем интервао + clearInterval(interval); + + //Устанавливаем значения + this.loaded = true; + this.#loadCount++; + + this.#Dispatch('loaded', { count: this.#loadCount, name: this.name }); + } + } + //Когда плеер загрузится будет ошибка CORS + } catch (error) { + //Очищаем интервао + clearInterval(interval); + + //Устанавливаем значения + this.loaded = true; + this.#loadCount++; + + this.#Dispatch('loaded', { count: this.#loadCount, name: this.name }); + } + }, 100); + } + + static Construct({ standart = false } = {}) { + _player.name = standart ? "tunime" : "kodik"; + } + + /** + * Созданние класса плеера + * @returns {Player} + */ + static Init(param) { + if (typeof _player === "undefined") { + _player = new Player(param); + } else if (param) { + Player.Construct(param); + } + return _player; + } + + /** + * Подписка на событие + * @param {keyof typeof player_callbacks} event - Название события (ключ из player_callbacks) + * @param {*} callback - Функция-обработчик для события + * @returns {void} + */ + on(event, callback) { + if (typeof callback !== "function") return; + if (this.#callbacks[event] === undefined) { + this.#callbacks[event] = []; + } + this.#callbacks[event].push(callback); + } + + + /** + * Вызов события + * @param {keyof typeof player_callbacks} event - Название события (ключ из player_callbacks) + * @param {object} data - Данные обратного вызова + * @returns {void} + */ + #Dispatch(event, data) { + if (this.#callbacks[event] === undefined) return; + this.#callbacks[event].forEach(callback => callback(data)); + } +} -export const Player = () => { return player; } \ No newline at end of file +export const IPlayer = Player; \ No newline at end of file diff --git a/javascript/pages/watch/mod_translation.js b/javascript/pages/watch/mod_translation.js index 953793b..1494e05 100644 --- a/javascript/pages/watch/mod_translation.js +++ b/javascript/pages/watch/mod_translation.js @@ -1,6 +1,9 @@ import { WindowManagement } from "../../modules/Windows.js"; import { $ID } from "../watch.js"; -import { Player } from "./mod_player.js"; +import { Franchises } from "./mod_franchise.js"; +import { IPlayer } from "./mod_player.js"; + +const Player = IPlayer.Init(); const WindowTranslation = { init: function () { @@ -16,13 +19,13 @@ const WindowTranslation = { setParameter('dubanime', e.target.checked); if (e.target.checked) { - Player().translation.key = "save-translations-" + $ID; + Player.CTranslation.lskey = "save-translations-" + $ID; } else { - Player().translation.key = "save-translations"; + Player.CTranslation.lskey = "save-translations"; } - Player().translation.saved = JSON.parse(localStorage.getItem(Player().translation.key)); - Player().translation.saved = Player().translation.saved ? Player().translation.saved : []; + Player.CTranslation.saved = JSON.parse(localStorage.getItem(Player.CTranslation.lskey)); + Player.CTranslation.saved = Player.CTranslation.saved ? Player.CTranslation.saved : []; //Сделать переключение избранных озвучек //Отключаем все в визуале @@ -30,10 +33,10 @@ const WindowTranslation = { $('.voice-save.select').removeClass("select"); //Добавляем только нужные - const data = Player().translation.saved; - //Проверим выбранное + const data = Player.CTranslation.saved; - if (data.findIndex(x => x == Player().translation.id) != -1) { + //Проверим выбранное + if (data.findIndex(x => x == Player.CTranslation.id) != -1) { $(".translations-wrapper > .button-stars").addClass("selected"); } @@ -49,7 +52,7 @@ const WindowTranslation = { $('.translation-param > .checkbox > input').prop('checked', $PARAMETERS.watch.dubanime); //Автоматическое скрытие окна при выборе озвучки - Player().translation.events.onselected((e) => { + Player.CTranslation.on('selected', () => { this.hide(); _windowTranslation.hide(); }); diff --git a/javascript/pages/watch/mod_ui.js b/javascript/pages/watch/mod_ui.js index e95ae5a..4638ea5 100644 --- a/javascript/pages/watch/mod_ui.js +++ b/javascript/pages/watch/mod_ui.js @@ -1,9 +1,9 @@ import { ScrollElementWithMouse, Sleep } from "../../modules/functions.js"; +import { ShowInfo } from "../../modules/Popup.js"; import { Tunime } from "../../modules/TunimeApi.js"; -import { $ID } from "../watch.js"; +import { $ID, Player } from "../watch.js"; import { ShowDwonloadWindow } from "./mod_download.js"; import { LoadScreen } from "./mod_load.js"; -import { Player } from "./mod_player.js"; import { LoadImageById } from "./mod_resource.js"; import { ShowTranslationWindow } from "./mod_translation.js"; import { UserRate } from "./mod_urate.js"; @@ -30,7 +30,8 @@ export function Functional() { { dom: "#share", func: ShareAnime }, { dom: "#btn-scroll", func: ShowPlayer }, { dom: '.translations-wrapper > .button-translation', func: ShowTranslationWindow }, - { dom: '.translations-wrapper > .button-stars', func: SaveVoice } + { dom: '.translations-wrapper > .button-stars', func: SaveVoice }, + { dom: '.title > .russian', func: CopyTitle } ] for (let i = 0; i < list.length; i++) { @@ -74,6 +75,11 @@ export function Functional() { LoadScreen.On('loaded', () => { AutoScrollFranchise(); }) + + //Отслеживаем изменение ориентации экрана для правильного отображения выбраного эпизода + window.addEventListener("orientationchange", function () { + OrientationChanged(); + }); } export function AutoScrollFranchise() { @@ -101,6 +107,15 @@ export function AutoScrollFranchise() { } } +async function CopyTitle() { + try { + await navigator.clipboard.writeText($(`.title > .russian`).text()); + ShowInfo('Название скопировано') + } catch (err) { + console.error('Failed to copy: ', err); + } +} + /** * Перезагрузка страницы */ @@ -226,18 +241,14 @@ function ScrollingElements() { } function ChangePlayer() { - if (Player().name == "tunime") { - Player().update(false); - } else { - Player().update(true); - } + Player.Switch(); } /** * Функция выбора текущей озвучки в избранное или удаление его */ function SaveVoice() { - Player().translation.favorites(Player().translation.id); + Player.CTranslation.Favorites(Player.CTranslation.id); } let enableCenter = false; @@ -315,4 +326,8 @@ function ShareAnime() { */ function ShowPlayer() { document.getElementById('kodik-player').scrollIntoView({ behavior: "smooth", block: "center" }); +} + +function OrientationChanged() { + Player.CEpisodes.Revise(); } \ No newline at end of file diff --git a/javascript/pages/watch/mod_wscore.js b/javascript/pages/watch/mod_wscore.js index f4eb9db..dba07d0 100644 --- a/javascript/pages/watch/mod_wscore.js +++ b/javascript/pages/watch/mod_wscore.js @@ -1,11 +1,13 @@ import { User } from "../../modules/ShikiUSR.js"; -import { Player } from "./mod_player.js"; import { WindowManagement } from "../../modules/Windows.js"; import { UserRate } from "./mod_urate.js"; import { SetSynchEnable, SYNC_ENABLE, Synch } from "./mod_sdata.js"; import { Private } from "./mod_private.js"; import { ShowCollectionWindow } from "./mod_collection.js"; import Collection from "../../modules/Collection.js"; +import { IPlayer } from "./mod_player.js"; + +const Player = IPlayer.Init(); const WindowScore = { comments: { @@ -85,7 +87,7 @@ const WindowScore = { } //Добавляем информацию о тексте - val += '\n' + searchString + ` ${Player().translation.name} - ${Player().translation.id}`; + val += '\n' + searchString + ` ${Player.CTranslation.name} - ${Player.CTranslation.id}`; } $('textarea.noten').val(val); @@ -132,40 +134,42 @@ const WindowScore = { SetNote(res.text); }); - Synch.Init().On((data) => { - try { - if (data === undefined) - return; + Player.on("inited", (results) => { + Synch.Init().On((data) => { + try { + if (data === undefined) + return; - const index = Player().data.findIndex(x => x.translation.id === data.kodik_dub); + const index = results.findIndex(x => x.translation.id === data.kodik_dub); - if (index === -1) - return; + if (index === -1) + return; - const title = Player().data[index].translation.title; - const date = new Date(data.date_update); + const title = results[index].translation.title; + const date = new Date(data.date_update); - $(`.sync-data > .voice`).text(title); - $(`.sync-data > .episode`).text(`${data.kodik_episode} Эпизод`); - $(`.sync-data > .time`).text(`${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}`); - } catch (error) { - console.log(error); - } + $(`.sync-data > .voice`).text(title); + $(`.sync-data > .episode`).text(`${data.kodik_episode} Эпизод`); + $(`.sync-data > .time`).text(`${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}`); + } catch (error) { + console.log(error); + } - }); + }); - Synch.Init().plugins.update.On((data) => { - const index = Player().data.findIndex(x => x.translation.id === data.kodik_dub); + Synch.Init().plugins.update.On((data) => { + const index = results.findIndex(x => x.translation.id === data.kodik_dub); - if (index === -1) - return; + if (index === -1) + return; - const title = Player().data[index].translation.title; - const date = data.date_update; + const title = results[index].translation.title; + const date = data.date_update; - $(`.sync-data > .voice`).text(title); - $(`.sync-data > .episode`).text(`${data.kodik_episode} Эпизод`); - $(`.sync-data > .time`).text(`${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}`); + $(`.sync-data > .voice`).text(title); + $(`.sync-data > .episode`).text(`${data.kodik_episode} Эпизод`); + $(`.sync-data > .time`).text(`${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}`); + }); }); }, diff --git a/sw.js b/sw.js index d377578..0d73ee4 100644 --- a/sw.js +++ b/sw.js @@ -1,5 +1,5 @@ -const version = '2.4.0'; -const hash = '00e74'; +const version = '2.5.1'; +const hash = '35513'; const cacheName = `pwa-tunime-${hash}-v${version}`; const appShellFilesToCache = [ // Директория: /images/genres