@ooneex/youtube 1.1.4 → 1.2.0
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/index.d.ts +29 -7
- package/dist/index.js +59 -20
- package/dist/index.js.map +5 -5
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -7,18 +7,40 @@ type YoutubeQualityOptionsType = QualityOptions;
|
|
|
7
7
|
type YoutubeFormatKeyWordType = keyof QualityOptions;
|
|
8
8
|
type YoutubeVideoQualityType = "2160p" | "1440p" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p" | "highest" | "lowest";
|
|
9
9
|
type YoutubeAudioQualityType = "highest" | "lowest";
|
|
10
|
+
type YoutubeTranscriptSegmentType = {
|
|
11
|
+
text: string;
|
|
12
|
+
start: number;
|
|
13
|
+
duration: number;
|
|
14
|
+
};
|
|
15
|
+
type YoutubeTranscriptAuthorType = {
|
|
16
|
+
name: string;
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
type YoutubeTranscriptMetadataType = {
|
|
20
|
+
title: string;
|
|
21
|
+
author: YoutubeTranscriptAuthorType;
|
|
22
|
+
thumbnail: string;
|
|
23
|
+
};
|
|
24
|
+
type YoutubeTranscriptResponseType = {
|
|
25
|
+
id: string;
|
|
26
|
+
lang: string;
|
|
27
|
+
transcript: YoutubeTranscriptSegmentType[];
|
|
28
|
+
metadata: YoutubeTranscriptMetadataType;
|
|
29
|
+
};
|
|
10
30
|
interface IYoutube {
|
|
11
|
-
|
|
12
|
-
getEmbedUrl(urlOrId: string): string | null;
|
|
13
|
-
getWatchUrl(urlOrId: string): string | null;
|
|
31
|
+
transcript(videoId: string): Promise<YoutubeTranscriptResponseType>;
|
|
14
32
|
}
|
|
15
33
|
declare class Youtube implements IYoutube {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
34
|
+
private static readonly BASE_URL;
|
|
35
|
+
private readonly apiKey;
|
|
36
|
+
constructor(apiKey?: string);
|
|
37
|
+
transcript(videoId: string): Promise<YoutubeTranscriptResponseType>;
|
|
38
|
+
static getWatchId(url: string): string | null;
|
|
39
|
+
static getEmbedUrl(urlOrId: string): string | null;
|
|
40
|
+
static getWatchUrl(urlOrId: string): string | null;
|
|
19
41
|
}
|
|
20
42
|
import { Exception } from "@ooneex/exception";
|
|
21
43
|
declare class YoutubeException extends Exception {
|
|
22
44
|
constructor(message: string, key: string, data?: Record<string, unknown>);
|
|
23
45
|
}
|
|
24
|
-
export { YoutubeVideoQualityType, YoutubeVideoProgressType, YoutubeVideoFormatType, YoutubeQualityOptionsType, YoutubeFormatOptionsType, YoutubeFormatKeyWordType, YoutubeException, YoutubeAudioQualityType, YoutubeArgsOptionsType, Youtube, IYoutube };
|
|
46
|
+
export { YoutubeVideoQualityType, YoutubeVideoProgressType, YoutubeVideoFormatType, YoutubeTranscriptSegmentType, YoutubeTranscriptResponseType, YoutubeTranscriptMetadataType, YoutubeTranscriptAuthorType, YoutubeQualityOptionsType, YoutubeFormatOptionsType, YoutubeFormatKeyWordType, YoutubeException, YoutubeAudioQualityType, YoutubeArgsOptionsType, Youtube, IYoutube };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,60 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// src/YoutubeException.ts
|
|
3
|
+
import { Exception } from "@ooneex/exception";
|
|
4
|
+
import { HttpStatus } from "@ooneex/http-status";
|
|
5
|
+
|
|
6
|
+
class YoutubeException extends Exception {
|
|
7
|
+
constructor(message, key, data = {}) {
|
|
8
|
+
super(message, {
|
|
9
|
+
key,
|
|
10
|
+
status: HttpStatus.Code.InternalServerError,
|
|
11
|
+
data
|
|
12
|
+
});
|
|
13
|
+
this.name = "YoutubeException";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
2
17
|
// src/Youtube.ts
|
|
3
18
|
class Youtube {
|
|
4
|
-
|
|
19
|
+
static BASE_URL = "https://transcriptapi.com/api/v2";
|
|
20
|
+
apiKey;
|
|
21
|
+
constructor(apiKey) {
|
|
22
|
+
this.apiKey = apiKey ?? Bun.env.YOUTUBE_TRANSCRIPT_API_KEY ?? "";
|
|
23
|
+
if (!this.apiKey) {
|
|
24
|
+
throw new YoutubeException("YouTube Transcript API key is required. Please set the YOUTUBE_TRANSCRIPT_API_KEY environment variable.", "API_KEY_REQUIRED");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async transcript(videoId) {
|
|
28
|
+
const params = new URLSearchParams({
|
|
29
|
+
video_url: videoId,
|
|
30
|
+
format: "json",
|
|
31
|
+
include_timestamp: "true",
|
|
32
|
+
send_metadata: "true"
|
|
33
|
+
});
|
|
34
|
+
const response = await fetch(`${Youtube.BASE_URL}/youtube/transcript?${params}`, {
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new YoutubeException(`Transcript API error: ${response.status} ${response.statusText}`, "TRANSCRIPT_FAILED", { videoId, status: response.status });
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
return {
|
|
44
|
+
id: data.video_id,
|
|
45
|
+
lang: data.language,
|
|
46
|
+
transcript: data.transcript,
|
|
47
|
+
metadata: {
|
|
48
|
+
title: data.metadata.title,
|
|
49
|
+
author: {
|
|
50
|
+
name: data.metadata.author_name,
|
|
51
|
+
url: data.metadata.author_url
|
|
52
|
+
},
|
|
53
|
+
thumbnail: data.metadata.thumbnail_url
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
static getWatchId(url) {
|
|
5
58
|
const patterns = [
|
|
6
59
|
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/watch\?.*&v=)([^&\n?#]+)/,
|
|
7
60
|
/youtube\.com\/shorts\/([^&\n?#]+)/
|
|
@@ -14,38 +67,24 @@ class Youtube {
|
|
|
14
67
|
}
|
|
15
68
|
return null;
|
|
16
69
|
}
|
|
17
|
-
getEmbedUrl(urlOrId) {
|
|
18
|
-
const videoId =
|
|
70
|
+
static getEmbedUrl(urlOrId) {
|
|
71
|
+
const videoId = Youtube.getWatchId(urlOrId) ?? urlOrId;
|
|
19
72
|
if (!/^[\w-]{10,12}$/.test(videoId)) {
|
|
20
73
|
return null;
|
|
21
74
|
}
|
|
22
75
|
return `https://www.youtube.com/embed/${videoId}`;
|
|
23
76
|
}
|
|
24
|
-
getWatchUrl(urlOrId) {
|
|
25
|
-
const videoId =
|
|
77
|
+
static getWatchUrl(urlOrId) {
|
|
78
|
+
const videoId = Youtube.getWatchId(urlOrId) ?? urlOrId;
|
|
26
79
|
if (!/^[\w-]{10,12}$/.test(videoId)) {
|
|
27
80
|
return null;
|
|
28
81
|
}
|
|
29
82
|
return `https://www.youtube.com/watch?v=${videoId}`;
|
|
30
83
|
}
|
|
31
84
|
}
|
|
32
|
-
// src/YoutubeException.ts
|
|
33
|
-
import { Exception } from "@ooneex/exception";
|
|
34
|
-
import { HttpStatus } from "@ooneex/http-status";
|
|
35
|
-
|
|
36
|
-
class YoutubeException extends Exception {
|
|
37
|
-
constructor(message, key, data = {}) {
|
|
38
|
-
super(message, {
|
|
39
|
-
key,
|
|
40
|
-
status: HttpStatus.Code.InternalServerError,
|
|
41
|
-
data
|
|
42
|
-
});
|
|
43
|
-
this.name = "YoutubeException";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
85
|
export {
|
|
47
86
|
YoutubeException,
|
|
48
87
|
Youtube
|
|
49
88
|
};
|
|
50
89
|
|
|
51
|
-
//# debugId=
|
|
90
|
+
//# debugId=0565A2533EB19F9364756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["src/
|
|
3
|
+
"sources": ["src/YoutubeException.ts", "src/Youtube.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import
|
|
6
|
-
"import {
|
|
5
|
+
"import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class YoutubeException extends Exception {\n constructor(message: string, key: string, data: Record<string, unknown> = {}) {\n super(message, {\n key,\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"YoutubeException\";\n }\n}\n",
|
|
6
|
+
"import type { IYoutube, YoutubeTranscriptResponseType } from \"./types\";\nimport { YoutubeException } from \"./YoutubeException\";\n\nexport class Youtube implements IYoutube {\n private static readonly BASE_URL = \"https://transcriptapi.com/api/v2\";\n\n private readonly apiKey: string;\n\n constructor(apiKey?: string) {\n this.apiKey = apiKey ?? Bun.env.YOUTUBE_TRANSCRIPT_API_KEY ?? \"\";\n\n if (!this.apiKey) {\n throw new YoutubeException(\n \"YouTube Transcript API key is required. Please set the YOUTUBE_TRANSCRIPT_API_KEY environment variable.\",\n \"API_KEY_REQUIRED\",\n );\n }\n }\n\n public async transcript(videoId: string): Promise<YoutubeTranscriptResponseType> {\n const params = new URLSearchParams({\n video_url: videoId,\n format: \"json\",\n include_timestamp: \"true\",\n send_metadata: \"true\",\n });\n\n const response = await fetch(`${Youtube.BASE_URL}/youtube/transcript?${params}`, {\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n throw new YoutubeException(\n `Transcript API error: ${response.status} ${response.statusText}`,\n \"TRANSCRIPT_FAILED\",\n { videoId, status: response.status },\n );\n }\n\n const data = await response.json();\n\n return {\n id: data.video_id,\n lang: data.language,\n transcript: data.transcript,\n metadata: {\n title: data.metadata.title,\n author: {\n name: data.metadata.author_name,\n url: data.metadata.author_url,\n },\n thumbnail: data.metadata.thumbnail_url,\n },\n };\n }\n\n public static getWatchId(url: string): string | null {\n const patterns = [\n /(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/|youtube\\.com\\/embed\\/|youtube\\.com\\/v\\/|youtube\\.com\\/watch\\?.*&v=)([^&\\n?#]+)/,\n /youtube\\.com\\/shorts\\/([^&\\n?#]+)/,\n ];\n\n for (const pattern of patterns) {\n const match = url.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n return null;\n }\n\n public static getEmbedUrl(urlOrId: string): string | null {\n const videoId = Youtube.getWatchId(urlOrId) ?? urlOrId;\n\n if (!/^[\\w-]{10,12}$/.test(videoId)) {\n return null;\n }\n\n return `https://www.youtube.com/embed/${videoId}`;\n }\n\n public static getWatchUrl(urlOrId: string): string | null {\n const videoId = Youtube.getWatchId(urlOrId) ?? urlOrId;\n\n if (!/^[\\w-]{10,12}$/.test(videoId)) {\n return null;\n }\n\n return `https://www.youtube.com/watch?v=${videoId}`;\n }\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;AAEO,MAAM,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": ";;AAAA;AACA;AAAA;AAEO,MAAM,yBAAyB,UAAU;AAAA,EAC9C,WAAW,CAAC,SAAiB,KAAa,OAAgC,CAAC,GAAG;AAAA,IAC5E,MAAM,SAAS;AAAA,MACb;AAAA,MACA,QAAQ,WAAW,KAAK;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,IACD,KAAK,OAAO;AAAA;AAEhB;;;ACTO,MAAM,QAA4B;AAAA,SACf,WAAW;AAAA,EAElB;AAAA,EAEjB,WAAW,CAAC,QAAiB;AAAA,IAC3B,KAAK,SAAS,UAAU,IAAI,IAAI,8BAA8B;AAAA,IAE9D,IAAI,CAAC,KAAK,QAAQ;AAAA,MAChB,MAAM,IAAI,iBACR,2GACA,kBACF;AAAA,IACF;AAAA;AAAA,OAGW,WAAU,CAAC,SAAyD;AAAA,IAC/E,MAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,mBAAmB;AAAA,MACnB,eAAe;AAAA,IACjB,CAAC;AAAA,IAED,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,+BAA+B,UAAU;AAAA,MAC/E,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,MAChC;AAAA,IACF,CAAC;AAAA,IAED,IAAI,CAAC,SAAS,IAAI;AAAA,MAChB,MAAM,IAAI,iBACR,yBAAyB,SAAS,UAAU,SAAS,cACrD,qBACA,EAAE,SAAS,QAAQ,SAAS,OAAO,CACrC;AAAA,IACF;AAAA,IAEA,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,IAEjC,OAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,MACjB,UAAU;AAAA,QACR,OAAO,KAAK,SAAS;AAAA,QACrB,QAAQ;AAAA,UACN,MAAM,KAAK,SAAS;AAAA,UACpB,KAAK,KAAK,SAAS;AAAA,QACrB;AAAA,QACA,WAAW,KAAK,SAAS;AAAA,MAC3B;AAAA,IACF;AAAA;AAAA,SAGY,UAAU,CAAC,KAA4B;AAAA,IACnD,MAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAAA,IAEA,WAAW,WAAW,UAAU;AAAA,MAC9B,MAAM,QAAQ,IAAI,MAAM,OAAO;AAAA,MAC/B,IAAI,QAAQ,IAAI;AAAA,QACd,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,SAGK,WAAW,CAAC,SAAgC;AAAA,IACxD,MAAM,UAAU,QAAQ,WAAW,OAAO,KAAK;AAAA,IAE/C,IAAI,CAAC,iBAAiB,KAAK,OAAO,GAAG;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAEA,OAAO,iCAAiC;AAAA;AAAA,SAG5B,WAAW,CAAC,SAAgC;AAAA,IACxD,MAAM,UAAU,QAAQ,WAAW,OAAO,KAAK;AAAA,IAE/C,IAAI,CAAC,iBAAiB,KAAK,OAAO,GAAG;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAEA,OAAO,mCAAmC;AAAA;AAE9C;",
|
|
9
|
+
"debugId": "0565A2533EB19F9364756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ooneex/youtube",
|
|
3
3
|
"description": "YouTube video downloader and metadata extraction library for fetching video information, thumbnails, and media streams",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"npm:publish": "bun publish --tolerate-republish --force --production --access public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@ooneex/exception": "1.
|
|
31
|
+
"@ooneex/exception": "1.2.0",
|
|
32
32
|
"@ooneex/http-status": "1.1.3",
|
|
33
33
|
"ytdlp-nodejs": "^2.3.5"
|
|
34
34
|
},
|