Skip to content

Commit

Permalink
Merge pull request #69 from Izumiko/newapi
Browse files Browse the repository at this point in the history
fix: 对接弹弹Play API认证
  • Loading branch information
Izumiko authored Jan 22, 2025
2 parents 74598c7 + 0784f84 commit 63501d9
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 100 deletions.
47 changes: 2 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,34 +64,10 @@

```conf
proxy_set_header Accept-Encoding "";
sub_filter '</body>' '<script src="https://jellyfin-danmaku.pages.dev/ede.user.js?noCors=1" defer></script></body>';
sub_filter '</body>' '<script src="https://jellyfin-danmaku.pages.dev/ede.user.js" defer></script></body>';
sub_filter_once on;
```

若需要本地代理弹弹play API,不使用CF Worker代理,则加入新的 location 块,否则删除上面网址中的`?noCors=1`:
```conf
location /ddplay-api/ {
proxy_pass https://api.dandanplay.net;
proxy_set_header Host $host;
# example.com 根据自己的域名设置,或直接设为*
add_header Access-Control-Allow-Origin "example.com";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization";
}
location /ddplay-api/api/v2/login {
rewrite ^/ddplay-api/api/v2/login(.*)$ /cors/https://api.dandanplay.net/api/v2/login$1 break;
proxy_pass https://ddplay-api.930524.xyz;
proxy_set_header Host $host;
# example.com 根据自己的域名设置,或直接设为*
add_header Access-Control-Allow-Origin "example.com";
add_header Access-Control-Allow-Methods "POST, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization";
}
```

- [`完整示例`](https://github.com/Izumiko/jellyfin-danmaku/issues/8)

#### 2.2 Caddy
Expand All @@ -109,31 +85,12 @@ example.com {
filter {
path /web/.*
search_pattern </body>
replacement "<script src=\"https://jellyfin-danmaku.pages.dev/ede.user.js?noCors=1\" defer></script></body>"
replacement "<script src=\"https://jellyfin-danmaku.pages.dev/ede.user.js\" defer></script></body>"
content_type text/html
}
reverse_proxy localhost:8096 {
header_up Accept-Encoding identity
}
# 若需要本地代理弹弹play API,不使用CF Worker代理,则加入下面两个handle_path,否则删除上面网址中的 ?noCors=1
handle_path /ddplay-api/* {
reverse_proxy https://api.dandanplay.net {
header_up Host {upstream_hostport}
header_down Access-Control-Allow-Origin "example.com"
header_down Access-Control-Allow-Methods "GET, POST, OPTIONS"
header_down Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
}
}
handle_path /ddplay-api/api/v2/login* {
rewrite * /cors/https://api.dandanplay.net/api/v2/login{http.request.uri.path}
reverse_proxy https://ddplay-api.930524.xyz {
header_up Host {upstream_hostport}
header_down Access-Control-Allow-Origin "example.com"
header_down Access-Control-Allow-Methods "POST, OPTIONS"
header_down Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
}
}
}
```

Expand Down
39 changes: 25 additions & 14 deletions cf_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ function handleOptions(request) {
}
}

async function generateSignature(appId, timestamp, path, appSecret) {
const data = appId + timestamp + path + appSecret;
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashBase64 = btoa(String.fromCharCode.apply(null, hashArray));
return hashBase64;
}

async function handleRequest(request) {
let response;
if (request.method === 'OPTIONS') {
Expand All @@ -48,9 +58,10 @@ async function handleRequest(request) {
return Forbidden(tUrlObj);
}

const body = request.method === 'POST' ? await request.json() : null;

// dandanplay login, compute sigh hash with appId and appSecret
if (request.method === 'POST' && tUrlObj.pathname === '/api/v2/login') {
let body = await request.json();
if (body.userName.length == 0 || body.password.length == 0) {
return new Response('{"error": "用户名或密码不能为空"}', {
status: 400,
Expand All @@ -65,22 +76,22 @@ async function handleRequest(request) {
body.hash = Array.from(new Uint8Array(hash))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');

response = await fetch(url, {
headers: request.headers,
body: JSON.stringify(body),
method: request.method,
});
response = new Response(await response.body, response);
response.headers.set('Access-Control-Allow-Origin', '*');
response.headers.set('Access-Control-Allow-Methods', 'GET, HEAD, POST, OPTIONS');

return response;
}

// handle dandanplay api auth
const timeStamp = Math.round(new Date().getTime() / 1000);
const apiPath = tUrlObj.pathname;
const signature = await generateSignature(appId, timeStamp, apiPath, appSecret);

response = await fetch(url, {
headers: request.headers,
body: request.body,
headers: {
...request.headers,
'X-AppId': appId,
'X-Signature': signature,
'X-Timestamp': timeStamp,
'X-Auth': '1',
},
body: body ? JSON.stringify(body) : null,
method: request.method,
});
response = new Response(await response.body, response);
Expand Down
52 changes: 11 additions & 41 deletions ede.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
// @description Jellyfin弹幕插件
// @namespace https://github.com/RyoLee
// @author RyoLee
// @version 1.51
// @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
Expand All @@ -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:当前状态打开
Expand Down Expand Up @@ -871,36 +863,14 @@
}

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) {
response.json = () => Promise.resolve(JSON.parse(response.responseText));
response.text = () => Promise.resolve(response.responseText);
response.ok = response.status >= 200 && response.status < 300;
resolve(response);
},
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) {
Expand Down

0 comments on commit 63501d9

Please sign in to comment.