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