multi_embed_player 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iframe_api/bilibili.d.ts +210 -0
- package/dist/iframe_api/bilibili.d.ts.map +1 -0
- package/dist/iframe_api/bilibili.js +1035 -0
- package/dist/iframe_api/bilibili.js.map +1 -0
- package/dist/iframe_api/niconico.d.ts +191 -0
- package/dist/iframe_api/niconico.d.ts.map +1 -0
- package/dist/iframe_api/niconico.js +325 -0
- package/dist/iframe_api/niconico.js.map +1 -0
- package/dist/iframe_api/soundcloud.d.ts +152 -0
- package/dist/iframe_api/soundcloud.d.ts.map +1 -0
- package/dist/iframe_api/soundcloud.js +360 -0
- package/dist/iframe_api/soundcloud.js.map +1 -0
- package/dist/iframe_api/youtube.d.ts +96 -0
- package/dist/iframe_api/youtube.d.ts.map +1 -0
- package/dist/iframe_api/youtube.js +269 -0
- package/dist/iframe_api/youtube.js.map +1 -0
- package/dist/multi_embed_player.d.ts +215 -0
- package/dist/multi_embed_player.d.ts.map +1 -0
- package/dist/multi_embed_player.js +921 -0
- package/dist/multi_embed_player.js.map +1 -0
- package/package.json +1 -1
- package/.github/workflows/build-and-deploy.yml +0 -44
- package/.gitmodules +0 -3
- package/browserExtention/chrome/background.js +0 -55
- package/browserExtention/chrome/extention.json +0 -1
- package/browserExtention/chrome/liteplayer.js +0 -26439
- package/browserExtention/chrome/manifest.json +0 -31
- package/browserExtention/chrome/player-selector.js +0 -1854
- package/browserExtention/firefox/background.js +0 -27
- package/browserExtention/firefox/extention.json +0 -1
- package/browserExtention/firefox/liteplayer.js +0 -26439
- package/browserExtention/firefox/manifest.json +0 -19
- package/browserExtention/firefox/player-selector.js +0 -1854
- package/documents/.hugo_build.lock +0 -0
- package/documents/archetypes/default.md +0 -5
- package/documents/assets/jsconfig.json +0 -11
- package/documents/content/docs/install.md +0 -103
- package/documents/content/docs/quickstart.md +0 -51
- package/documents/content/docs/reference/HTML.md +0 -31
- package/documents/content/docs/reference/_index.md +0 -10
- package/documents/content/docs/reference/error_code.md +0 -23
- package/documents/content/docs/reference/iframe_api.md +0 -737
- package/documents/content/docs/reference/iframe_class.md +0 -230
- package/documents/content/docs/reference/multi_embed_player_class.md +0 -113
- package/documents/content/docs/reference/reserved_words.md +0 -71
- package/documents/content/docs/usage/GDPR_mode.md +0 -77
- package/documents/content/docs/usage/_index.md +0 -10
- package/documents/content/docs/usage/custom_playlist.md +0 -239
- package/documents/content/docs/usage/embed_api.md +0 -163
- package/documents/content/docs/usage/embed_various_service.md +0 -81
- package/documents/content/docs/usage/thumbnail_click.md +0 -57
- package/documents/go.mod +0 -8
- package/documents/go.sum +0 -14
- package/documents/hugo.toml +0 -18
- package/documents/layouts/partials/docs/sidebar.html +0 -117
- package/documents/layouts/partials/landing/features.html +0 -47
- package/documents/layouts/robots.txt +0 -4
- package/documents/static/_headers +0 -7
- package/documents/static/localStorageCheck.html +0 -27
- package/documents/static/no_extention.json +0 -1
- package/example.html +0 -27
- package/extention.json +0 -1
- package/icon/video_not_found.odg +0 -0
- package/icon/video_not_found.svgz +0 -0
- package/iframe_api/bilibili.ts +0 -1095
- package/iframe_api/niconico.ts +0 -429
- package/iframe_api/soundcloud.ts +0 -450
- package/iframe_api/youtube.ts +0 -311
- package/multi_embed_player.ts +0 -989
- package/player_api_gate/bilibili-api-gate/cgi/cpp/bilibili-api-gate-cgi.cpp +0 -281
- package/player_api_gate/bilibili-api-gate/cgi/go/src.go +0 -46
- package/player_api_gate/bilibili-api-gate/cloudflare_workers/package-lock.json +0 -1356
- package/player_api_gate/bilibili-api-gate/cloudflare_workers/package.json +0 -12
- package/player_api_gate/bilibili-api-gate/cloudflare_workers/src/index.js +0 -50
- package/player_api_gate/bilibili-api-gate/cloudflare_workers/wrangler.toml +0 -3
- package/player_api_gate/iframe-api-ts/.editorconfig +0 -12
- package/player_api_gate/iframe-api-ts/.prettierrc +0 -6
- package/player_api_gate/iframe-api-ts/package-lock.json +0 -3054
- package/player_api_gate/iframe-api-ts/package.json +0 -18
- package/player_api_gate/iframe-api-ts/src/bilibili.ts +0 -49
- package/player_api_gate/iframe-api-ts/src/index.ts +0 -35
- package/player_api_gate/iframe-api-ts/src/niconico.ts +0 -95
- package/player_api_gate/iframe-api-ts/src/soundcloud.ts +0 -38
- package/player_api_gate/iframe-api-ts/src/types.ts +0 -115
- package/player_api_gate/iframe-api-ts/src/url-proxy.ts +0 -29
- package/player_api_gate/iframe-api-ts/src/utils.ts +0 -82
- package/player_api_gate/iframe-api-ts/src/youtube.ts +0 -41
- package/player_api_gate/iframe-api-ts/test/bilibili.spec.ts +0 -47
- package/player_api_gate/iframe-api-ts/test/env.d.ts +0 -3
- package/player_api_gate/iframe-api-ts/test/index.spec.ts +0 -59
- package/player_api_gate/iframe-api-ts/test/niconico.spec.ts +0 -55
- package/player_api_gate/iframe-api-ts/test/soundcloud.spec.ts +0 -55
- package/player_api_gate/iframe-api-ts/test/tsconfig.json +0 -8
- package/player_api_gate/iframe-api-ts/test/url-proxy.spec.ts +0 -46
- package/player_api_gate/iframe-api-ts/test/youtube.spec.ts +0 -45
- package/player_api_gate/iframe-api-ts/tsconfig.json +0 -45
- package/player_api_gate/iframe-api-ts/vitest.config.mts +0 -11
- package/player_api_gate/iframe-api-ts/worker-configuration.d.ts +0 -5768
- package/player_api_gate/iframe-api-ts/wrangler.jsonc +0 -47
- package/player_api_gate/iframe_api/.editorconfig +0 -13
- package/player_api_gate/iframe_api/.prettierrc +0 -6
- package/player_api_gate/iframe_api/package-lock.json +0 -1307
- package/player_api_gate/iframe_api/package.json +0 -12
- package/player_api_gate/iframe_api/src/bilibili_api.js +0 -60
- package/player_api_gate/iframe_api/src/index.js +0 -47
- package/player_api_gate/iframe_api/src/niconico_api.js +0 -112
- package/player_api_gate/iframe_api/src/soundcloud_api.js +0 -57
- package/player_api_gate/iframe_api/src/url_proxy.js +0 -28
- package/player_api_gate/iframe_api/src/youtube_api.js +0 -44
- package/player_api_gate/iframe_api/wrangler.toml +0 -51
- package/player_api_gate/niconico-imager/cgi/go/src.go +0 -74
- package/player_api_gate/niconico-imager/cloudflare_workers/package-lock.json +0 -2175
- package/player_api_gate/niconico-imager/cloudflare_workers/package.json +0 -12
- package/player_api_gate/niconico-imager/cloudflare_workers/src/index.js +0 -78
- package/player_api_gate/niconico-imager/cloudflare_workers/wrangler.toml +0 -3
- package/test_script.html +0 -172
- package/tsconfig.json +0 -36
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "iframe-api-ts",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"scripts": {
|
|
6
|
-
"deploy": "wrangler deploy",
|
|
7
|
-
"dev": "wrangler dev",
|
|
8
|
-
"start": "wrangler dev",
|
|
9
|
-
"test": "vitest",
|
|
10
|
-
"cf-typegen": "wrangler types"
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"@cloudflare/vitest-pool-workers": "^0.8.19",
|
|
14
|
-
"typescript": "^5.5.2",
|
|
15
|
-
"vitest": "~3.2.0",
|
|
16
|
-
"wrangler": "^4.20.0"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { Env, BilibiliResponse } from './types';
|
|
2
|
-
import { createErrorResponse, createSuccessResponse, getImageAsBase64 } from './utils';
|
|
3
|
-
|
|
4
|
-
export const handleBilibiliRequest = async (request: Request, env: Env): Promise<Response> => {
|
|
5
|
-
const { searchParams } = new URL(request.url);
|
|
6
|
-
const videoid = searchParams.get('videoid');
|
|
7
|
-
|
|
8
|
-
if (!videoid) {
|
|
9
|
-
return createErrorResponse(
|
|
10
|
-
'plese set bvid in query string example ?videoid=BV1Yq4y1Z785',
|
|
11
|
-
'bilibili api'
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const url = `https://api.bilibili.com/x/web-interface/view?bvid=${videoid}`;
|
|
16
|
-
let response: Response;
|
|
17
|
-
let resdata: BilibiliResponse;
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
if (env.PROXY_VIA_URL) {
|
|
21
|
-
response = await fetch(env.PROXY_VIA_URL, {
|
|
22
|
-
method: "POST",
|
|
23
|
-
body: JSON.stringify({ urls: [url] }),
|
|
24
|
-
headers: {
|
|
25
|
-
"content-type": "application/json",
|
|
26
|
-
"user-agent": env.PROXY_AUTH || ""
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
const resTmpData = await response.json();
|
|
30
|
-
resdata = JSON.parse(resTmpData[url]);
|
|
31
|
-
} else {
|
|
32
|
-
response = await fetch(url);
|
|
33
|
-
resdata = await response.json();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (resdata.code === 0 && searchParams.get("image_base64") === '1') {
|
|
37
|
-
if (resdata.data?.pic) {
|
|
38
|
-
resdata.image_base64 = await getImageAsBase64(resdata.data.pic);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return createSuccessResponse(resdata);
|
|
43
|
-
} catch (error) {
|
|
44
|
-
return createErrorResponse(
|
|
45
|
-
'Failed to fetch bilibili data',
|
|
46
|
-
'bilibili api'
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
import { parseWhiteList, isWhiteListAllowed } from './utils';
|
|
3
|
-
import { handleBilibiliRequest } from './bilibili';
|
|
4
|
-
import { handleYouTubeRequest } from './youtube';
|
|
5
|
-
import { handleNiconicoRequest } from './niconico';
|
|
6
|
-
import { handleSoundCloudRequest } from './soundcloud';
|
|
7
|
-
import { handleUrlProxyRequest } from './url-proxy';
|
|
8
|
-
|
|
9
|
-
export default {
|
|
10
|
-
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
11
|
-
const whiteList = parseWhiteList(env.WhiteList);
|
|
12
|
-
|
|
13
|
-
if (!isWhiteListAllowed(request, whiteList)) {
|
|
14
|
-
return new Response("access from this origin is not allowed", { status: 403 });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const url = new URL(request.url);
|
|
18
|
-
const route = url.searchParams.get("route");
|
|
19
|
-
|
|
20
|
-
switch (route) {
|
|
21
|
-
case 'url_proxy':
|
|
22
|
-
return handleUrlProxyRequest(request, env);
|
|
23
|
-
case 'niconico':
|
|
24
|
-
return handleNiconicoRequest(request, env);
|
|
25
|
-
case 'bilibili':
|
|
26
|
-
return handleBilibiliRequest(request, env);
|
|
27
|
-
case 'soundcloud':
|
|
28
|
-
return handleSoundCloudRequest(request, env);
|
|
29
|
-
case 'youtube':
|
|
30
|
-
return handleYouTubeRequest(request, env);
|
|
31
|
-
default:
|
|
32
|
-
return new Response("route not found", { status: 404 });
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
} satisfies ExportedHandler<Env>;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { Env, NiconicoResponse } from './types';
|
|
2
|
-
import { createErrorResponse, createSuccessResponse, getImageAsBase64, randomString, xmlSearch } from './utils';
|
|
3
|
-
|
|
4
|
-
export const handleNiconicoRequest = async (request: Request, env: Env): Promise<Response> => {
|
|
5
|
-
const { searchParams } = new URL(request.url);
|
|
6
|
-
const videoid = searchParams.get('videoid');
|
|
7
|
-
|
|
8
|
-
if (!videoid) {
|
|
9
|
-
return createErrorResponse(
|
|
10
|
-
'plese set videoid in query string',
|
|
11
|
-
'niconico api'
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
let returnData: NiconicoResponse = {};
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
if (env.NON_PROFIT === "TRUE") {
|
|
19
|
-
const url = `https://snapshot.search.nicovideo.jp/api/v2/snapshot/video/contents/search?q&fields=contentId,title,thumbnailUrl,userId,channelId,startTime,lengthSeconds&filters[contentId][0]=${videoid}&_sort=-viewCounter&_limit=1&_context=${randomString(10)}`;
|
|
20
|
-
|
|
21
|
-
const response = await fetch(url);
|
|
22
|
-
const res = await response.json();
|
|
23
|
-
|
|
24
|
-
if (res.meta.status === 200) {
|
|
25
|
-
returnData.status = "success";
|
|
26
|
-
returnData.videoid = videoid;
|
|
27
|
-
returnData.title = res.data[0].title;
|
|
28
|
-
returnData.thumbnail_url = res.data[0].thumbnailUrl;
|
|
29
|
-
returnData.length = res.data[0].lengthSeconds;
|
|
30
|
-
returnData.view_count = res.data[0].viewCounter;
|
|
31
|
-
returnData.publish_time = res.data[0].startTime;
|
|
32
|
-
} else {
|
|
33
|
-
returnData.status = "invalid videoid";
|
|
34
|
-
returnData.thumbnail_url = "";
|
|
35
|
-
}
|
|
36
|
-
} else {
|
|
37
|
-
const url = `https://ext.nicovideo.jp/api/getthumbinfo/${videoid}`;
|
|
38
|
-
const response = await fetch(url,{
|
|
39
|
-
headers: {
|
|
40
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
const res = await response.text();
|
|
44
|
-
|
|
45
|
-
const imageUrl = xmlSearch(res, "thumbnail_url");
|
|
46
|
-
const predictLong = 43 + 2 * (videoid.length - 2);
|
|
47
|
-
let finalImageUrl = imageUrl;
|
|
48
|
-
|
|
49
|
-
if (imageUrl.length > predictLong) {
|
|
50
|
-
finalImageUrl += ".L";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const xmlVideoid = xmlSearch(res, "video_id");
|
|
54
|
-
const title = xmlSearch(res, "title");
|
|
55
|
-
const description = xmlSearch(res, "description");
|
|
56
|
-
const length = xmlSearch(res, "length");
|
|
57
|
-
const viewCount = xmlSearch(res, "view_counter");
|
|
58
|
-
const commentCount = xmlSearch(res, "comment_num");
|
|
59
|
-
const mylistCount = xmlSearch(res, "mylist_counter");
|
|
60
|
-
const publishTime = xmlSearch(res, "first_retrieve");
|
|
61
|
-
const embedable = xmlSearch(res, "embeddable");
|
|
62
|
-
const genre = xmlSearch(res, "genre");
|
|
63
|
-
|
|
64
|
-
if (imageUrl === "<?xml version=") {
|
|
65
|
-
returnData.status = "invalid videoid";
|
|
66
|
-
returnData.thumbnail_url = "";
|
|
67
|
-
} else {
|
|
68
|
-
returnData.thumbnail_url = finalImageUrl;
|
|
69
|
-
|
|
70
|
-
if (searchParams.get("image_base64") === '1') {
|
|
71
|
-
returnData.image_base64 = await getImageAsBase64(finalImageUrl);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
returnData.status = "success";
|
|
75
|
-
returnData.videoid = xmlVideoid;
|
|
76
|
-
returnData.title = title;
|
|
77
|
-
returnData.description = description;
|
|
78
|
-
returnData.length = length;
|
|
79
|
-
returnData.view_count = viewCount;
|
|
80
|
-
returnData.comment_count = commentCount;
|
|
81
|
-
returnData.mylist_count = mylistCount;
|
|
82
|
-
returnData.publish_time = publishTime;
|
|
83
|
-
returnData.embedable = embedable;
|
|
84
|
-
returnData.genre = genre;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return createSuccessResponse(returnData);
|
|
89
|
-
} catch (error) {
|
|
90
|
-
return createErrorResponse(
|
|
91
|
-
'Failed to fetch niconico data',
|
|
92
|
-
'niconico api'
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Env, SoundCloudResponse } from './types';
|
|
2
|
-
import { createErrorResponse, createSuccessResponse, getImageAsBase64 } from './utils';
|
|
3
|
-
|
|
4
|
-
export const handleSoundCloudRequest = async (request: Request, env: Env): Promise<Response> => {
|
|
5
|
-
const { searchParams } = new URL(request.url);
|
|
6
|
-
const videoid = searchParams.get('videoid');
|
|
7
|
-
|
|
8
|
-
if (!videoid) {
|
|
9
|
-
return createErrorResponse(
|
|
10
|
-
'plese set indentify music id in query string example ?videoid=557856309',
|
|
11
|
-
'soundcloud api'
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const numericRegex = /^[0-9]+$/;
|
|
16
|
-
let url: string;
|
|
17
|
-
|
|
18
|
-
if (numericRegex.test(videoid)) {
|
|
19
|
-
url = `https://soundcloud.com/oembed?url=https%3A//api.soundcloud.com/tracks/${videoid}&format=json`;
|
|
20
|
-
} else {
|
|
21
|
-
url = `https://soundcloud.com/oembed?url=https%3A//soundcloud.com/${videoid}&format=json`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const response = await fetch(url);
|
|
26
|
-
let resdata: SoundCloudResponse = await response.json();
|
|
27
|
-
|
|
28
|
-
if (searchParams.get("image_base64") === '1' && resdata.thumbnail_url) {
|
|
29
|
-
resdata.image_base64 = await getImageAsBase64(resdata.thumbnail_url);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return createSuccessResponse(resdata);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return createSuccessResponse({
|
|
35
|
-
status: "error not found?"
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
interface Env {
|
|
2
|
-
WhiteList?: string;
|
|
3
|
-
PROXY_VIA_URL?: string;
|
|
4
|
-
PROXY_AUTH?: string;
|
|
5
|
-
NON_PROFIT?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface BaseResponse {
|
|
9
|
-
status: string;
|
|
10
|
-
message?: string;
|
|
11
|
-
product_type?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface BilibiliResponse extends BaseResponse {
|
|
15
|
-
code?: number;
|
|
16
|
-
data?: {
|
|
17
|
-
bvid: string;
|
|
18
|
-
aid: number;
|
|
19
|
-
videos: number;
|
|
20
|
-
tid: number;
|
|
21
|
-
tname: string;
|
|
22
|
-
copyright: number;
|
|
23
|
-
pic: string;
|
|
24
|
-
title: string;
|
|
25
|
-
pubdate: number;
|
|
26
|
-
ctime: number;
|
|
27
|
-
desc: string;
|
|
28
|
-
duration: number;
|
|
29
|
-
owner: {
|
|
30
|
-
mid: number;
|
|
31
|
-
name: string;
|
|
32
|
-
face: string;
|
|
33
|
-
};
|
|
34
|
-
stat: {
|
|
35
|
-
aid: number;
|
|
36
|
-
view: number;
|
|
37
|
-
danmaku: number;
|
|
38
|
-
reply: number;
|
|
39
|
-
favorite: number;
|
|
40
|
-
coin: number;
|
|
41
|
-
share: number;
|
|
42
|
-
now_rank: number;
|
|
43
|
-
his_rank: number;
|
|
44
|
-
like: number;
|
|
45
|
-
dislike: number;
|
|
46
|
-
evaluation: string;
|
|
47
|
-
argue_msg: string;
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
image_base64?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface YouTubeResponse extends BaseResponse {
|
|
54
|
-
title?: string;
|
|
55
|
-
author_name?: string;
|
|
56
|
-
author_url?: string;
|
|
57
|
-
type?: string;
|
|
58
|
-
height?: number;
|
|
59
|
-
width?: number;
|
|
60
|
-
version?: string;
|
|
61
|
-
provider_name?: string;
|
|
62
|
-
provider_url?: string;
|
|
63
|
-
thumbnail_height?: number;
|
|
64
|
-
thumbnail_width?: number;
|
|
65
|
-
thumbnail_url?: string;
|
|
66
|
-
html?: string;
|
|
67
|
-
image_base64?: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
interface NiconicoResponse extends BaseResponse {
|
|
71
|
-
videoid?: string;
|
|
72
|
-
title?: string;
|
|
73
|
-
description?: string;
|
|
74
|
-
thumbnail_url?: string;
|
|
75
|
-
length?: string | number;
|
|
76
|
-
view_count?: string | number;
|
|
77
|
-
comment_count?: string;
|
|
78
|
-
mylist_count?: string;
|
|
79
|
-
publish_time?: string;
|
|
80
|
-
embedable?: string;
|
|
81
|
-
genre?: string;
|
|
82
|
-
image_base64?: string;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
interface SoundCloudResponse extends BaseResponse {
|
|
86
|
-
version?: string;
|
|
87
|
-
type?: string;
|
|
88
|
-
provider_name?: string;
|
|
89
|
-
provider_url?: string;
|
|
90
|
-
height?: number;
|
|
91
|
-
width?: number;
|
|
92
|
-
title?: string;
|
|
93
|
-
description?: string;
|
|
94
|
-
thumbnail_url?: string;
|
|
95
|
-
html?: string;
|
|
96
|
-
author_name?: string;
|
|
97
|
-
author_url?: string;
|
|
98
|
-
image_base64?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
interface CommonHeaders {
|
|
102
|
-
'content-type': string;
|
|
103
|
-
'Access-Control-Allow-Origin': string;
|
|
104
|
-
'cache-control': string;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export type {
|
|
108
|
-
Env,
|
|
109
|
-
BaseResponse,
|
|
110
|
-
BilibiliResponse,
|
|
111
|
-
YouTubeResponse,
|
|
112
|
-
NiconicoResponse,
|
|
113
|
-
SoundCloudResponse,
|
|
114
|
-
CommonHeaders
|
|
115
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
import { createErrorResponse, createProxyHeaders } from './utils';
|
|
3
|
-
|
|
4
|
-
export const handleUrlProxyRequest = async (request: Request, env: Env): Promise<Response> => {
|
|
5
|
-
const { searchParams } = new URL(request.url);
|
|
6
|
-
const proxyUrl = searchParams.get('url');
|
|
7
|
-
|
|
8
|
-
if (!proxyUrl) {
|
|
9
|
-
return createErrorResponse(
|
|
10
|
-
'plese set url in query string example ?url=https://i.ytimg.com/vi/giXeMGjDkgk/hqdefault.jpg',
|
|
11
|
-
'url proxy api'
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const fetchData = await fetch(proxyUrl);
|
|
17
|
-
const imageData = await fetchData.arrayBuffer();
|
|
18
|
-
const contentType = fetchData.headers.get("content-type") || "application/octet-stream";
|
|
19
|
-
|
|
20
|
-
return new Response(imageData, {
|
|
21
|
-
headers: createProxyHeaders(contentType)
|
|
22
|
-
});
|
|
23
|
-
} catch (error) {
|
|
24
|
-
return createErrorResponse(
|
|
25
|
-
'Failed to fetch proxied resource',
|
|
26
|
-
'url proxy api'
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import type { CommonHeaders } from './types';
|
|
2
|
-
|
|
3
|
-
export const createCommonHeaders = (): CommonHeaders => ({
|
|
4
|
-
'content-type': 'application/json',
|
|
5
|
-
'Access-Control-Allow-Origin': '*',
|
|
6
|
-
'cache-control': 'max-age=2592000'
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export const createProxyHeaders = (contentType: string): Record<string, string> => ({
|
|
10
|
-
'content-type': contentType,
|
|
11
|
-
'Access-Control-Allow-Origin': '*',
|
|
12
|
-
'cache-control': 'max-age=2592000'
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export const createErrorResponse = (message: string, productType: string): Response => {
|
|
16
|
-
const errorData = {
|
|
17
|
-
status: 'failed',
|
|
18
|
-
message,
|
|
19
|
-
product_type: productType
|
|
20
|
-
};
|
|
21
|
-
return new Response(JSON.stringify(errorData), {
|
|
22
|
-
headers: createCommonHeaders()
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const createSuccessResponse = (data: any): Response => {
|
|
27
|
-
return new Response(JSON.stringify(data), {
|
|
28
|
-
headers: createCommonHeaders()
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const getImageAsBase64 = async (imageUrl: string): Promise<string> => {
|
|
33
|
-
const imageData = await (await fetch(imageUrl)).arrayBuffer();
|
|
34
|
-
let binary = '';
|
|
35
|
-
const bytes = new Uint8Array(imageData);
|
|
36
|
-
const len = bytes.byteLength;
|
|
37
|
-
for (let i = 0; i < len; i++) {
|
|
38
|
-
binary += String.fromCharCode(bytes[i]);
|
|
39
|
-
}
|
|
40
|
-
return "data:image/jpeg;base64," + btoa(binary);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const randomString = (length: number): string => {
|
|
44
|
-
return [...Array(length)].map(() => (~~(Math.random() * 36)).toString(36)).join('');
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const xmlSearch = (data: string, searchString: string, start = 0): string => {
|
|
48
|
-
const startTag = `<${searchString}>`;
|
|
49
|
-
const endTag = `</${searchString}>`;
|
|
50
|
-
const startIndex = data.indexOf(startTag, start);
|
|
51
|
-
const endIndex = data.indexOf(endTag, start);
|
|
52
|
-
|
|
53
|
-
if (startIndex === -1 || endIndex === -1) {
|
|
54
|
-
return '';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return data.substring(startIndex + startTag.length, endIndex);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const isWhiteListAllowed = (request: Request, whiteList: string[]): boolean => {
|
|
61
|
-
if (whiteList.length === 0) {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const origin = request.headers.get("origin");
|
|
66
|
-
if (!origin) {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return whiteList.includes(origin);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const parseWhiteList = (whiteListEnv?: string): string[] => {
|
|
74
|
-
if (typeof whiteListEnv === "undefined") {
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
return JSON.parse(whiteListEnv);
|
|
79
|
-
} catch {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { Env, YouTubeResponse } from './types';
|
|
2
|
-
import { createErrorResponse, createSuccessResponse, getImageAsBase64 } from './utils';
|
|
3
|
-
|
|
4
|
-
export const handleYouTubeRequest = async (request: Request, env: Env): Promise<Response> => {
|
|
5
|
-
const { searchParams } = new URL(request.url);
|
|
6
|
-
const videoid = searchParams.get('videoid');
|
|
7
|
-
|
|
8
|
-
if (!videoid) {
|
|
9
|
-
return createErrorResponse(
|
|
10
|
-
'plese set indentify music id in query string example ?videoid=W6tZW00lix1',
|
|
11
|
-
'youtube api'
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const url = `https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${videoid}&format=json`;
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const response = await fetch(url);
|
|
19
|
-
let resdata: YouTubeResponse;
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
resdata = await response.json();
|
|
23
|
-
|
|
24
|
-
if (searchParams.get("image_base64") === '1' && resdata.thumbnail_url) {
|
|
25
|
-
resdata.image_base64 = await getImageAsBase64(resdata.thumbnail_url);
|
|
26
|
-
}
|
|
27
|
-
} catch {
|
|
28
|
-
resdata = {
|
|
29
|
-
title: "",
|
|
30
|
-
status: "failed notfound?"
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return createSuccessResponse(resdata);
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return createErrorResponse(
|
|
37
|
-
'Failed to fetch youtube data',
|
|
38
|
-
'youtube api'
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'vitest';
|
|
2
|
-
import { SELF } from 'cloudflare:test';
|
|
3
|
-
import { handleBilibiliRequest } from '../src/bilibili';
|
|
4
|
-
|
|
5
|
-
test('bilibili API handles missing videoid', async () => {
|
|
6
|
-
const request = new Request('http://example.com/?route=bilibili');
|
|
7
|
-
const env = {};
|
|
8
|
-
|
|
9
|
-
const response = await handleBilibiliRequest(request, env);
|
|
10
|
-
const data = await response.json();
|
|
11
|
-
|
|
12
|
-
expect(data.status).toBe('failed');
|
|
13
|
-
expect(data.message).toContain('plese set bvid');
|
|
14
|
-
expect(data.product_type).toBe('bilibili api');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('bilibili API handles valid request', async () => {
|
|
18
|
-
const request = new Request('http://example.com/?route=bilibili&videoid=BV1Yq4y1Z785');
|
|
19
|
-
const env = {};
|
|
20
|
-
|
|
21
|
-
const response = await handleBilibiliRequest(request, env);
|
|
22
|
-
|
|
23
|
-
expect(response.status).toBe(200);
|
|
24
|
-
expect(response.headers.get('content-type')).toBe('application/json');
|
|
25
|
-
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('bilibili API handles proxy mode', async () => {
|
|
29
|
-
const request = new Request('http://example.com/?route=bilibili&videoid=BV1Yq4y1Z785');
|
|
30
|
-
const env = {
|
|
31
|
-
PROXY_VIA_URL: 'https://proxy.example.com',
|
|
32
|
-
PROXY_AUTH: 'test-auth'
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const response = await handleBilibiliRequest(request, env);
|
|
36
|
-
|
|
37
|
-
expect(response.status).toBe(200);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('bilibili API handles image_base64 parameter', async () => {
|
|
41
|
-
const request = new Request('http://example.com/?route=bilibili&videoid=BV1Yq4y1Z785&image_base64=1');
|
|
42
|
-
const env = {};
|
|
43
|
-
|
|
44
|
-
const response = await handleBilibiliRequest(request, env);
|
|
45
|
-
|
|
46
|
-
expect(response.status).toBe(200);
|
|
47
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { env, createExecutionContext, waitOnExecutionContext, SELF } from 'cloudflare:test';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import worker from '../src/index';
|
|
4
|
-
|
|
5
|
-
// For now, you'll need to do something like this to get a correctly-typed
|
|
6
|
-
// `Request` to pass to `worker.fetch()`.
|
|
7
|
-
const IncomingRequest = Request<unknown, IncomingRequestCfProperties>;
|
|
8
|
-
|
|
9
|
-
describe('Iframe API Router', () => {
|
|
10
|
-
it('handles unknown route', async () => {
|
|
11
|
-
const response = await SELF.fetch('http://example.com/?route=unknown');
|
|
12
|
-
expect(response.status).toBe(404);
|
|
13
|
-
expect(await response.text()).toBe('route not found');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('handles whitelist restriction', async () => {
|
|
17
|
-
const request = new IncomingRequest('http://example.com/?route=youtube&videoid=test', {
|
|
18
|
-
headers: { 'origin': 'https://unauthorized.com' }
|
|
19
|
-
});
|
|
20
|
-
const ctx = createExecutionContext();
|
|
21
|
-
const testEnv = { ...env, WhiteList: '["https://authorized.com"]' };
|
|
22
|
-
const response = await worker.fetch(request, testEnv, ctx);
|
|
23
|
-
await waitOnExecutionContext(ctx);
|
|
24
|
-
|
|
25
|
-
expect(response.status).toBe(403);
|
|
26
|
-
expect(await response.text()).toBe('access from this origin is not allowed');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('allows request without whitelist', async () => {
|
|
30
|
-
const response = await SELF.fetch('http://example.com/?route=youtube&videoid=dQw4w9WgXcQ');
|
|
31
|
-
expect(response.status).toBe(200);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('routes to bilibili', async () => {
|
|
35
|
-
const response = await SELF.fetch('http://example.com/?route=bilibili&videoid=BV1Yq4y1Z785');
|
|
36
|
-
expect(response.status).toBe(200);
|
|
37
|
-
expect(response.headers.get('content-type')).toBe('application/json');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('routes to youtube', async () => {
|
|
41
|
-
const response = await SELF.fetch('http://example.com/?route=youtube&videoid=dQw4w9WgXcQ');
|
|
42
|
-
expect(response.status).toBe(200);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('routes to niconico', async () => {
|
|
46
|
-
const response = await SELF.fetch('http://example.com/?route=niconico&videoid=sm9');
|
|
47
|
-
expect(response.status).toBe(200);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('routes to soundcloud', async () => {
|
|
51
|
-
const response = await SELF.fetch('http://example.com/?route=soundcloud&videoid=557856309');
|
|
52
|
-
expect(response.status).toBe(200);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('routes to url_proxy', async () => {
|
|
56
|
-
const response = await SELF.fetch('http://example.com/?route=url_proxy&url=https://httpbin.org/json');
|
|
57
|
-
expect(response.status).toBe(200);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'vitest';
|
|
2
|
-
import { handleNiconicoRequest } from '../src/niconico';
|
|
3
|
-
|
|
4
|
-
test('niconico API handles missing videoid', async () => {
|
|
5
|
-
const request = new Request('http://example.com/?route=niconico');
|
|
6
|
-
const env = {};
|
|
7
|
-
|
|
8
|
-
const response = await handleNiconicoRequest(request, env);
|
|
9
|
-
const data = await response.json();
|
|
10
|
-
|
|
11
|
-
expect(data.status).toBe('failed');
|
|
12
|
-
expect(data.message).toContain('plese set videoid');
|
|
13
|
-
expect(data.product_type).toBe('niconico api');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
test('niconico API handles valid request in normal mode', async () => {
|
|
17
|
-
const request = new Request('http://example.com/?route=niconico&videoid=sm9');
|
|
18
|
-
const env = {};
|
|
19
|
-
|
|
20
|
-
const response = await handleNiconicoRequest(request, env);
|
|
21
|
-
|
|
22
|
-
expect(response.status).toBe(200);
|
|
23
|
-
expect(response.headers.get('content-type')).toBe('application/json');
|
|
24
|
-
expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('niconico API handles valid request in non-profit mode', async () => {
|
|
28
|
-
const request = new Request('http://example.com/?route=niconico&videoid=sm9');
|
|
29
|
-
const env = { NON_PROFIT: 'TRUE' };
|
|
30
|
-
|
|
31
|
-
const response = await handleNiconicoRequest(request, env);
|
|
32
|
-
|
|
33
|
-
expect(response.status).toBe(200);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('niconico API handles image_base64 parameter', async () => {
|
|
37
|
-
const request = new Request('http://example.com/?route=niconico&videoid=sm9&image_base64=1');
|
|
38
|
-
const env = {};
|
|
39
|
-
|
|
40
|
-
const response = await handleNiconicoRequest(request, env);
|
|
41
|
-
|
|
42
|
-
expect(response.status).toBe(200);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('niconico API handles invalid video id', async () => {
|
|
46
|
-
const request = new Request('http://example.com/?route=niconico&videoid=invalid_id');
|
|
47
|
-
const env = {};
|
|
48
|
-
|
|
49
|
-
const response = await handleNiconicoRequest(request, env);
|
|
50
|
-
const data = await response.json();
|
|
51
|
-
|
|
52
|
-
expect(response.status).toBe(200);
|
|
53
|
-
// The actual API may still return success for some invalid IDs, depending on the service response
|
|
54
|
-
expect(data.status).toBeDefined();
|
|
55
|
-
});
|