diff --git a/static/ede.user.js b/static/ede.user.js
index 67c50fa..9a7403f 100644
--- a/static/ede.user.js
+++ b/static/ede.user.js
@@ -3,13 +3,12 @@
// @description Jellyfin弹幕插件
// @namespace https://github.com/RyoLee
// @author RyoLee
-// @version 1.49
+// @version 1.52
// @copyright 2022, RyoLee (https://github.com/RyoLee)
// @license MIT; https://raw.githubusercontent.com/Izumiko/jellyfin-danmaku/jellyfin/LICENSE
// @icon https://github.githubassets.com/pinned-octocat.svg
// @updateURL https://cdn.jsdelivr.net/gh/Izumiko/jellyfin-danmaku@gh-pages/ede.user.js
// @downloadURL https://cdn.jsdelivr.net/gh/Izumiko/jellyfin-danmaku@gh-pages/ede.user.js
-// @grant GM_xmlhttpRequest
// @connect *
// @match *://*/*/web/index.html
// @match *://*/web/index.html
@@ -24,16 +23,9 @@
return;
}
// ------ configs start------
- const isInTampermonkey = !(typeof GM_xmlhttpRequest === 'undefined');
- const isLocalCors = (!isInTampermonkey && document.currentScript?.src) ? new URL(document.currentScript?.src).searchParams.has("noCors") : false;
const corsProxy = 'https://ddplay-api.930524.xyz/cors/';
- const apiPrefix = isInTampermonkey
- ? 'https://api.dandanplay.net'
- : isLocalCors
- ? `${window.location.origin}/ddplay-api`
- : corsProxy + 'https://api.dandanplay.net';
- // const apiPrefix = 'https://api.930524.xyz';
- const authPrefix = isLocalCors ? apiPrefix : corsProxy + 'https://api.dandanplay.net'; // 在Worker上计算Hash
+ const apiPrefix = corsProxy + 'https://api.dandanplay.net';
+ const authPrefix = corsProxy + 'https://api.dandanplay.net'; // 在Worker上计算Hash
let ddplayStatus = JSON.parse(localStorage.getItem('ddplayStatus')) || { isLogin: false, token: '', tokenExpire: 0 };
const check_interval = 200;
// 0:当前状态关闭 1:当前状态打开
@@ -49,10 +41,25 @@
is: 'paper-icon-button-light',
};
const uiAnchorStr = 'pause';
- const uiQueryStr = '.osdTimeText';
+ const uiQueryStr = '.btnPause';
const mediaContainerQueryStr = "div[data-type='video-osd']";
const mediaQueryStr = 'video';
+ let isNewJellyfin = true;
+ let itemId = '';
+
+ // Intercept XMLHttpRequest
+ const originalOpen = XMLHttpRequest.prototype.open;
+ XMLHttpRequest.prototype.open = function (_, url) {
+ this.addEventListener('load', function () {
+ if (url.endsWith('PlaybackInfo')) {
+ const res = JSON.parse(this.responseText);
+ itemId = res.MediaSources[0].Id;
+ }
+ });
+ originalOpen.apply(this, arguments);
+ };
+
const displayButtonOpts = {
title: '弹幕开关',
id: 'displayDanmaku',
@@ -166,7 +173,7 @@
@@ -292,7 +299,7 @@
showDebugInfo(`字体:${window.ede.fontFamily}`);
window.ede.fontOptions = document.getElementById("danmakuFontOptions").value;
window.localStorage.setItem('danmakuFontOptions', window.ede.fontOptions);
- showDebugInfo(`字体选項:${window.ede.fontOptions}`);
+ showDebugInfo(`字体选项:${window.ede.fontOptions}`);
reloadDanmaku('reload');
closeModal();
} catch (e) {
@@ -450,7 +457,7 @@
/* eslint-disable */
/* https://cdn.jsdelivr.net/npm/danmaku/dist/danmaku.min.js */
// prettier-ignore
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Danmaku=e()}(this,(function(){"use strict";var t=function(){if("undefined"==typeof document)return"transform";for(var t=["oTransform","msTransform","mozTransform","webkitTransform","transform"],e=document.createElement("div").style,i=0;i0&&a!==1/0?Math.ceil(a):1*!!o.strokeStyle,h.font=o.font,t.width=t.width||Math.max(1,Math.ceil(h.measureText(t.text).width)+2*a),t.height=t.height||Math.ceil(function(t,e){if(s[t])return s[t];var i=12,n=t.match(/(\d+(?:\.\d+)?)(px|%|em|rem)(?:\s*\/\s*(\d+(?:\.\d+)?)(px|%|em|rem)?)?/);if(n){var r=1*n[1]||10,h=n[2],o=1*n[3]||1.2,a=n[4];"%"===h&&(r*=e.container/100),"em"===h&&(r*=e.container),"rem"===h&&(r*=e.root),"px"===a&&(i=o),"%"===a&&(i=r*o/100),"em"===a&&(i=r*o),"rem"===a&&(i=e.root*o),void 0===a&&(i=r*o)}return s[t]=i,i}(o.font,e))+2*a,r.width=t.width*n,r.height=t.height*n,h.scale(n,n),o)h[d]=o[d];var u=0;switch(o.textBaseline){case"top":case"hanging":u=a;break;case"middle":u=t.height>>1;break;default:u=t.height-a}return o.strokeStyle&&h.strokeText(t.text,a,u),h.fillText(t.text,a,u),r}function h(t){return 1*window.getComputedStyle(t,null).getPropertyValue("font-size").match(/(.+)px/)[1]}var o={name:"canvas",init:function(t){var e=document.createElement("canvas");return e.context=e.getContext("2d"),e._fontSize={root:h(document.getElementsByTagName("html")[0]),container:h(t)},e},clear:function(t,e){t.context.clearRect(0,0,t.width,t.height);for(var i=0;ir)return!0;var h=e._.duration+t.time-i,o=e._.width+s.width,a=e.media?s.time:s._utc,d=o*(i-a)*n/e._.duration,u=e._.width-d;return h>e._.duration*u/(e._.width+s.width)}for(var r=this._.space[t.mode],h=0,o=0,a=1;a=u){o=a;break}s(d,t)&&(h=a)}var m=r[h].range,c={range:m+t.height,time:this.media?t.time:t._utc,width:t.width,height:t.height};return r.splice(h+1,o-h-1,c),"bottom"===t.mode?this._.height-t.height-m%this._.height:m%(this._.height-t.height)}var d="undefined"!=typeof window&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame)||function(t){return setTimeout(t,50/3)},u="undefined"!=typeof window&&(window.cancelAnimationFrame||window.mozCancelAnimationFrame||window.webkitCancelAnimationFrame)||clearTimeout;function m(t,e,i){for(var n=0,s=0,r=t.length;s=t[n=s+r>>1][e]?s=n:r=n;return t[s]&&i=0;u--)o=this._.runningList[u],r-(d=this.media?o.time:o._utc)>this._.duration&&(n(this._.stage,o),this._.runningList.splice(u,1));for(var m=[];this._.position=r));)r-d>this._.duration||(this.media&&(o._utc=s-(this.media.currentTime-o.time)),m.push(o)),++this._.position;for(e(this._.stage,m),u=0;u>1),i(this._.stage,o)}}}(this._.engine.framing.bind(this),this._.engine.setup.bind(this),this._.engine.render.bind(this),this._.engine.remove.bind(this));return this._.requestID=d((function t(){n.call(i),i._.requestID=d(t)})),this}function g(){return!this._.visible||this._.paused||(this._.paused=!0,u(this._.requestID),this._.requestID=0),this}function _(){if(!this.media)return this;this.clear(),f(this._.space);var t=m(this.comments,"time",this.media.currentTime);return this._.position=Math.max(0,t-1),this}function v(t){t.play=p.bind(this),t.pause=g.bind(this),t.seeking=_.bind(this),this.media.addEventListener("play",t.play),this.media.addEventListener("pause",t.pause),this.media.addEventListener("playing",t.play),this.media.addEventListener("waiting",t.pause),this.media.addEventListener("seeking",t.seeking)}function w(t){this.media.removeEventListener("play",t.play),this.media.removeEventListener("pause",t.pause),this.media.removeEventListener("playing",t.play),this.media.removeEventListener("waiting",t.pause),this.media.removeEventListener("seeking",t.seeking),t.play=null,t.pause=null,t.seeking=null}function y(t){this._={},this.container=t.container||document.createElement("div"),this.media=t.media,this._.visible=!0,this.engine=(t.engine||"DOM").toLowerCase(),this._.engine="canvas"===this.engine?o:i,this._.requestID=0,this._.speed=Math.max(0,t.speed)||144,this._.duration=4,this.comments=t.comments||[],this.comments.sort((function(t,e){return t.time-e.time}));for(var e=0;e0&&a!==1/0?Math.ceil(a):1*!!o.strokeStyle,h.font=o.font,t.width=t.width||Math.max(1,Math.ceil(h.measureText(t.text).width)+2*a),t.height=t.height||Math.ceil(function(t,e){if(s[t])return s[t];var i=12,n=t.match(/(\d+(?:\.\d+)?)(px|%|em|rem)(?:\s*\/\s*(\d+(?:\.\d+)?)(px|%|em|rem)?)?/);if(n){var r=1*n[1]||10,h=n[2],o=1*n[3]||1.2,a=n[4];"%"===h&&(r*=e.container/100),"em"===h&&(r*=e.container),"rem"===h&&(r*=e.root),"px"===a&&(i=o),"%"===a&&(i=r*o/100),"em"===a&&(i=r*o),"rem"===a&&(i=e.root*o),void 0===a&&(i=r*o)}return s[t]=i,i}(o.font,e))+2*a,r.width=t.width*n,r.height=t.height*n,h.scale(n,n),o)h[d]=o[d];var u=0;switch(o.textBaseline){case"top":case"hanging":u=a;break;case"middle":u=t.height>>1;break;default:u=t.height-a}return o.strokeStyle&&h.strokeText(t.text,a,u),h.fillText(t.text,a,u),r}function h(t){return 1*window.getComputedStyle(t,null).getPropertyValue("font-size").match(/(.+)px/)[1]}var o={name:"canvas",init:function(t){var e=document.createElement("canvas");return e.context=e.getContext("2d"),e._fontSize={root:h(document.getElementsByTagName("html")[0]),container:h(t)},e},clear:function(t,e){t.context.clearRect(0,0,t.width,t.height);for(var i=0;i=t[n=s+r>>1][e]?s=n:r=n;return t[s]&&ir)return!0;var h=e._.duration+t.time-i,o=e._.width+s.width,a=e.media?s.time:s._utc,d=o*(i-a)*n/e._.duration,u=e._.width-d;return h>e._.duration*u/(e._.width+s.width)}for(var r=this._.space[t.mode],h=0,o=0,a=1;a=u){o=a;break}s(d,t)&&(h=a)}var m=r[h].range,c={range:m+t.height,time:this.media?t.time:t._utc,width:t.width,height:t.height};return r.splice(h+1,o-h-1,c),"bottom"===t.mode?this._.height-t.height-m%this._.height:m%(this._.height-t.height)}function g(){if(!this._.visible||!this._.paused)return this;if(this._.paused=!1,this.media)for(var t=0;t=0;u--)a=this._.runningList[u],h-(d=this.media?a.time:a._utc)>this._.duration&&(n(this._.stage,a),this._.runningList.splice(u,1));for(var m=[];this._.position=h));)h-d>this._.duration||(this.media&&(a._utc=r-(this.media.currentTime-a.time)),m.push(a)),++this._.position;for(e(this._.stage,m),u=0;u>1),i(this._.stage,a)}}}(this._.engine.framing.bind(this),this._.engine.setup.bind(this),this._.engine.render.bind(this),this._.engine.remove.bind(this));return this._.requestID=a((function t(e){n.call(i,e),i._.requestID=a(t)})),this}function _(){return!this._.visible||this._.paused||(this._.paused=!0,d(this._.requestID),this._.requestID=0),this}function v(){if(!this.media)return this;this.clear(),l(this._.space);var t=u(this.comments,"time",this.media.currentTime);return this._.position=Math.max(0,t-1),this}function w(t){t.play=g.bind(this),t.pause=_.bind(this),t.seeking=v.bind(this),this.media.addEventListener("play",t.play),this.media.addEventListener("pause",t.pause),this.media.addEventListener("playing",t.play),this.media.addEventListener("waiting",t.pause),this.media.addEventListener("seeking",t.seeking)}function y(t){this.media.removeEventListener("play",t.play),this.media.removeEventListener("pause",t.pause),this.media.removeEventListener("playing",t.play),this.media.removeEventListener("waiting",t.pause),this.media.removeEventListener("seeking",t.seeking),t.play=null,t.pause=null,t.seeking=null}function x(t){this._={},this.container=t.container||document.createElement("div"),this.media=t.media,this._.visible=!0,this.engine=(t.engine||"DOM").toLowerCase(),this._.engine="canvas"===this.engine?o:i,this._.requestID=0,this._.speed=Math.max(0,t.speed)||144,this._.duration=4,this.comments=t.comments||[],this.comments.sort((function(t,e){return t.time-e.time}));for(var e=0;e setTimeout(resolve, 200));
- let sessionInfo = await ApiClient.getSessions({
- userId: ApiClient.getCurrentUserId(),
- deviceId: ApiClient.deviceId(),
- });
- if (!sessionInfo[0].NowPlayingItem) {
- await new Promise(resolve => setTimeout(resolve, 150));
- continue;
+ if (isNewJellyfin) {
+ // params: userId, itemId
+ playingInfo = await ApiClient.getItem(ApiClient.getCurrentUserId(), itemId);
+ } else {
+ let sessionInfo = await ApiClient.getSessions({
+ userId: ApiClient.getCurrentUserId(),
+ deviceId: ApiClient.deviceId(),
+ });
+ if (!sessionInfo[0].NowPlayingItem) {
+ await new Promise(resolve => setTimeout(resolve, 150));
+ continue;
+ }
+ playingInfo = sessionInfo[0].NowPlayingItem;
}
- playingInfo = sessionInfo[0].NowPlayingItem;
}
showDebugInfo('获取Item信息成功: ' + (playingInfo.SeriesName || playingInfo.Name));
return playingInfo;
}
function makeGetRequest(url) {
- if (isInTampermonkey) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: "GET",
- url: url,
- headers: {
- "Accept-Encoding": "gzip,br",
- "Accept": "application/json"
- },
- onload: function (response) {
- resolve(response.responseText);
- },
- onerror: function (error) {
- reject(error);
- }
- });
- });
- } else {
- return fetch(url, {
- method: 'GET',
- headers: {
- "Accept-Encoding": "gzip,br",
- "Accept": "application/json",
- "User-Agent": navigator.userAgent
- }
- });
- }
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ "Accept-Encoding": "gzip,br",
+ "Accept": "application/json",
+ "User-Agent": navigator.userAgent
+ }
+ });
}
async function getEpisodeInfo(is_auto = true) {
@@ -924,9 +917,9 @@
}
window.ede.curEpOffset = window.localStorage.getItem(_episode_key_offset) || 0;
- let searchUrl = apiPrefix + '/api/v2/search/episodes?anime=' + animeName + '&withRelated=true';
+ let searchUrl = apiPrefix + '/api/v2/search/episodes?anime=' + animeName;
let animaInfo = await makeGetRequest(searchUrl)
- .then((response) => isInTampermonkey ? JSON.parse(response) : response.json())
+ .then((response) => response.json())
.catch((error) => {
showDebugInfo('查询失败:', error);
return null;
@@ -935,9 +928,9 @@
const seriesInfo = await ApiClient.getItem(ApiClient.getCurrentUserId(), item.SeriesId || item.Id);
animeName = seriesInfo.OriginalTitle;
if (animeName?.length > 0) {
- searchUrl = apiPrefix + '/api/v2/search/episodes?anime=' + animeName + '&withRelated=true';
+ searchUrl = apiPrefix + '/api/v2/search/episodes?anime=' + animeName;
animaInfo = await makeGetRequest(searchUrl)
- .then((response) => isInTampermonkey ? JSON.parse(response) : response.json())
+ .then((response) => response.json())
.catch((error) => {
showDebugInfo('查询失败:', error);
return null;
@@ -1001,7 +994,7 @@
const url_ext = apiPrefix + '/api/v2/extcomment?url=';
try {
let response = await makeGetRequest(url_all);
- let data = isInTampermonkey ? JSON.parse(response) : await response.json();
+ let data = await response.json();
const matchBili = /^\[BiliBili\]/;
let hasBili = false;
if ((danmakuFilter & 1) !== 1) {
@@ -1014,7 +1007,7 @@
}
let comments = data.comments;
response = await makeGetRequest(url_related);
- data = isInTampermonkey ? JSON.parse(response) : await response.json();
+ data = await response.json();
showDebugInfo('第三方弹幕源个数:' + data.relateds.length);
if (data.relateds.length > 0) {
@@ -1037,7 +1030,7 @@
// 获取第三方弹幕
await Promise.all(src.map(async (s) => {
const response = await makeGetRequest(url_ext + encodeURIComponent(s));
- const data = isInTampermonkey ? JSON.parse(response) : await response.json();
+ const data = await response.json();
comments = comments.concat(data.comments);
}));
}
@@ -1055,7 +1048,7 @@
for (let i = 0; i < 2; i++) {
try {
const response = await makeGetRequest(url);
- const data = isInTampermonkey ? JSON.parse(response) : await response.json();
+ const data = await response.json();
showDebugInfo('弹幕下载成功: ' + data.comments.length);
return data.comments;
} catch (error) {
@@ -1076,7 +1069,7 @@
async function getCommentsByPluginApi(jellyfinItemId) {
const path = window.location.pathname.replace(/\/web\/(index\.html)?/, '/api/danmu/');
const url = window.location.origin + path + jellyfinItemId + '/raw';
- const response = await makeGetRequest(url);
+ const response = await fetch(url);
if (!response.ok) {
return null;
}
@@ -1165,7 +1158,7 @@
showDebugInfo(`弹幕模式过滤:${window.ede.danmakuModeFilter}`);
showDebugInfo(`弹幕字号:${window.ede.fontSize}`);
showDebugInfo(`弹幕字体:${window.ede.fontFamily}`);
- showDebugInfo(`弹幕字体选項:${window.ede.fontOptions}`);
+ showDebugInfo(`弹幕字体选项:${window.ede.fontOptions}`);
showDebugInfo(`屏幕分辨率:${window.screen.width}x${window.screen.height}`);
if (window.ede.curEpOffset !== 0) showDebugInfo(`当前弹幕偏移:${window.ede.curEpOffset} 秒`);
@@ -1491,12 +1484,29 @@
});
};
+ const compareVersions = (version1, version2) => {
+ if (typeof version1 !== 'string') return -1;
+ if (typeof version2 !== 'string') return 1;
+ const v1 = version1.split('.').map(Number);
+ const v2 = version2.split('.').map(Number);
+
+ for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
+ const n1 = v1[i] || 0;
+ const n2 = v2[i] || 0;
+
+ if (n1 > n2) return 1;
+ if (n1 < n2) return -1;
+ }
+
+ return 0;
+ }
+
waitForElement('.htmlvideoplayer').then(() => {
if (!window.ede) {
window.ede = new EDE();
- var materialIcon = document.querySelector('.material-icons');
- var fontFamily = window.getComputedStyle(materialIcon).fontFamily;
+ const materialIcon = document.querySelector('.material-icons');
+ const fontFamily = window.getComputedStyle(materialIcon).fontFamily;
if (fontFamily === '"Font Awesome 6 Pro"') {
danmaku_icons = ['fa-comment-slash', 'fa-comment'];
log_icons = ['fa-toilet-paper-slash', 'fa-toilet-paper'];
@@ -1507,8 +1517,21 @@
}
(async () => {
- while (!(await ApiClient.getSessions())) {
- await new Promise((resolve) => setTimeout(resolve, 200));
+ isNewJellyfin = compareVersions(ApiClient?._appVersion, '10.10.0') >= 0;
+ // showDebugInfo(`isNewJellyfin: ${isNewJellyfin}`);
+ if (isNewJellyfin) {
+ let retry = 0;
+ while (!itemId) {
+ await new Promise((resolve) => setTimeout(resolve, 200));
+ retry++;
+ if (retry > 10) {
+ throw new Error('获取itemId失败');
+ }
+ }
+ } else {
+ while (!(await ApiClient.getSessions())) {
+ await new Promise((resolve) => setTimeout(resolve, 200));
+ }
}
setInterval(() => {