yt-transcript-strapi-plugin 0.0.10 → 0.0.12
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/_chunks/App-DKY3upWd.js +0 -1
- package/dist/_chunks/App-DXPFDMBH.mjs +0 -1
- package/dist/_chunks/en-B4KWt_jN.js +0 -1
- package/dist/_chunks/en-Byx4XI2L.mjs +0 -1
- package/dist/_chunks/index-Cf76FLRe.mjs +0 -1
- package/dist/_chunks/index-CpWYZFmv.js +0 -1
- package/dist/admin/index.js +0 -1
- package/dist/admin/index.mjs +0 -1
- package/dist/server/index.js +3 -21
- package/dist/server/index.mjs +3 -21
- package/dist/server/src/content-types/index.d.ts +0 -3
- package/dist/server/src/content-types/transcript/index.d.ts +0 -3
- package/dist/server/src/index.d.ts +0 -3
- package/dist/server/src/utils/fetch-transcript.d.ts +1 -3
- package/package.json +1 -1
- package/dist/_chunks/App-DKY3upWd.js.map +0 -1
- package/dist/_chunks/App-DXPFDMBH.mjs.map +0 -1
- package/dist/_chunks/en-B4KWt_jN.js.map +0 -1
- package/dist/_chunks/en-Byx4XI2L.mjs.map +0 -1
- package/dist/_chunks/index-Cf76FLRe.mjs.map +0 -1
- package/dist/_chunks/index-CpWYZFmv.js.map +0 -1
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/index.mjs.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server/index.mjs.map +0 -1
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -60,9 +60,6 @@ const attributes = {
|
|
|
60
60
|
videoId: {
|
|
61
61
|
type: "string"
|
|
62
62
|
},
|
|
63
|
-
thumbnailUrl: {
|
|
64
|
-
type: "string"
|
|
65
|
-
},
|
|
66
63
|
fullTranscript: {
|
|
67
64
|
type: "richtext"
|
|
68
65
|
},
|
|
@@ -120,9 +117,8 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
120
117
|
const readableTranscript = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
121
118
|
console.log("Human readable transcript generated.");
|
|
122
119
|
const payload = {
|
|
120
|
+
videoId,
|
|
123
121
|
title: transcriptData?.title || "No title found",
|
|
124
|
-
videoId: transcriptData?.videoId,
|
|
125
|
-
thumbnailUrl: transcriptData?.thumbnailUrl || "No thumbnail URL found",
|
|
126
122
|
fullTranscript: transcriptData?.fullTranscript,
|
|
127
123
|
transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,
|
|
128
124
|
readableTranscript
|
|
@@ -180,7 +176,7 @@ async function initializeModel({
|
|
|
180
176
|
maxTokens: 1e3
|
|
181
177
|
});
|
|
182
178
|
}
|
|
183
|
-
const fetchTranscript = async (
|
|
179
|
+
const fetchTranscript = async (videoId) => {
|
|
184
180
|
console.log("Fetching Transcript - Calling fetchTranscript Utils");
|
|
185
181
|
const { Innertube } = await import("youtubei.js");
|
|
186
182
|
console.log("Creating YouTube instance");
|
|
@@ -190,10 +186,7 @@ const fetchTranscript = async (identifier) => {
|
|
|
190
186
|
retrieve_player: false
|
|
191
187
|
});
|
|
192
188
|
try {
|
|
193
|
-
|
|
194
|
-
return url.split("?")[0];
|
|
195
|
-
};
|
|
196
|
-
const info2 = await youtube.getInfo(identifier);
|
|
189
|
+
const info2 = await youtube.getInfo(videoId);
|
|
197
190
|
const transcriptData = await info2.getTranscript();
|
|
198
191
|
console.log("Transcript data fetched");
|
|
199
192
|
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {
|
|
@@ -206,20 +199,12 @@ const fetchTranscript = async (identifier) => {
|
|
|
206
199
|
};
|
|
207
200
|
});
|
|
208
201
|
console.log("Transcript with time codes generated");
|
|
209
|
-
console.log("Cleaning thumbnail URL");
|
|
210
202
|
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => segment.snippet.text).join(" ");
|
|
211
203
|
console.log(fullTranscript, "full transcript");
|
|
212
204
|
console.log("Full transcript generated");
|
|
213
|
-
console.log("Getting basic info");
|
|
214
|
-
const title = info2.basic_info?.title;
|
|
215
|
-
const videoId = info2.basic_info?.id;
|
|
216
|
-
console.log("Getting thumbnail URL");
|
|
217
|
-
const thumbnailUrl = info2?.basic_info?.thumbnail[0]?.url;
|
|
218
205
|
console.log("Returning transcript data");
|
|
219
206
|
return {
|
|
220
207
|
videoId,
|
|
221
|
-
...title ? { title } : { title: "No title found" },
|
|
222
|
-
...thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: "" },
|
|
223
208
|
fullTranscript,
|
|
224
209
|
transcriptWithTimeCodes
|
|
225
210
|
};
|
|
@@ -277,8 +262,6 @@ const service = ({ strapi: strapi2 }) => ({
|
|
|
277
262
|
},
|
|
278
263
|
async findTranscript(videoId) {
|
|
279
264
|
console.log("Finding transcript for videoId:", videoId);
|
|
280
|
-
const test = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript");
|
|
281
|
-
console.log("Test:", test);
|
|
282
265
|
const transcriptData = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").findFirst({
|
|
283
266
|
filters: { videoId }
|
|
284
267
|
});
|
|
@@ -308,4 +291,3 @@ const index = {
|
|
|
308
291
|
middlewares
|
|
309
292
|
};
|
|
310
293
|
module.exports = index;
|
|
311
|
-
//# sourceMappingURL=index.js.map
|
package/dist/server/index.mjs
CHANGED
|
@@ -37,9 +37,6 @@ const attributes = {
|
|
|
37
37
|
videoId: {
|
|
38
38
|
type: "string"
|
|
39
39
|
},
|
|
40
|
-
thumbnailUrl: {
|
|
41
|
-
type: "string"
|
|
42
|
-
},
|
|
43
40
|
fullTranscript: {
|
|
44
41
|
type: "richtext"
|
|
45
42
|
},
|
|
@@ -97,9 +94,8 @@ const controller = ({ strapi: strapi2 }) => ({
|
|
|
97
94
|
const readableTranscript = await strapi2.plugin("yt-transcript-strapi-plugin").service("service").generateHumanReadableTranscript(transcriptData.fullTranscript);
|
|
98
95
|
console.log("Human readable transcript generated.");
|
|
99
96
|
const payload = {
|
|
97
|
+
videoId,
|
|
100
98
|
title: transcriptData?.title || "No title found",
|
|
101
|
-
videoId: transcriptData?.videoId,
|
|
102
|
-
thumbnailUrl: transcriptData?.thumbnailUrl || "No thumbnail URL found",
|
|
103
99
|
fullTranscript: transcriptData?.fullTranscript,
|
|
104
100
|
transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,
|
|
105
101
|
readableTranscript
|
|
@@ -157,7 +153,7 @@ async function initializeModel({
|
|
|
157
153
|
maxTokens: 1e3
|
|
158
154
|
});
|
|
159
155
|
}
|
|
160
|
-
const fetchTranscript = async (
|
|
156
|
+
const fetchTranscript = async (videoId) => {
|
|
161
157
|
console.log("Fetching Transcript - Calling fetchTranscript Utils");
|
|
162
158
|
const { Innertube } = await import("youtubei.js");
|
|
163
159
|
console.log("Creating YouTube instance");
|
|
@@ -167,10 +163,7 @@ const fetchTranscript = async (identifier) => {
|
|
|
167
163
|
retrieve_player: false
|
|
168
164
|
});
|
|
169
165
|
try {
|
|
170
|
-
|
|
171
|
-
return url.split("?")[0];
|
|
172
|
-
};
|
|
173
|
-
const info2 = await youtube.getInfo(identifier);
|
|
166
|
+
const info2 = await youtube.getInfo(videoId);
|
|
174
167
|
const transcriptData = await info2.getTranscript();
|
|
175
168
|
console.log("Transcript data fetched");
|
|
176
169
|
const transcriptWithTimeCodes = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {
|
|
@@ -183,20 +176,12 @@ const fetchTranscript = async (identifier) => {
|
|
|
183
176
|
};
|
|
184
177
|
});
|
|
185
178
|
console.log("Transcript with time codes generated");
|
|
186
|
-
console.log("Cleaning thumbnail URL");
|
|
187
179
|
const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => segment.snippet.text).join(" ");
|
|
188
180
|
console.log(fullTranscript, "full transcript");
|
|
189
181
|
console.log("Full transcript generated");
|
|
190
|
-
console.log("Getting basic info");
|
|
191
|
-
const title = info2.basic_info?.title;
|
|
192
|
-
const videoId = info2.basic_info?.id;
|
|
193
|
-
console.log("Getting thumbnail URL");
|
|
194
|
-
const thumbnailUrl = info2?.basic_info?.thumbnail[0]?.url;
|
|
195
182
|
console.log("Returning transcript data");
|
|
196
183
|
return {
|
|
197
184
|
videoId,
|
|
198
|
-
...title ? { title } : { title: "No title found" },
|
|
199
|
-
...thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: "" },
|
|
200
185
|
fullTranscript,
|
|
201
186
|
transcriptWithTimeCodes
|
|
202
187
|
};
|
|
@@ -254,8 +239,6 @@ const service = ({ strapi: strapi2 }) => ({
|
|
|
254
239
|
},
|
|
255
240
|
async findTranscript(videoId) {
|
|
256
241
|
console.log("Finding transcript for videoId:", videoId);
|
|
257
|
-
const test = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript");
|
|
258
|
-
console.log("Test:", test);
|
|
259
242
|
const transcriptData = await strapi2.documents("plugin::yt-transcript-strapi-plugin.transcript").findFirst({
|
|
260
243
|
filters: { videoId }
|
|
261
244
|
});
|
|
@@ -287,4 +270,3 @@ const index = {
|
|
|
287
270
|
export {
|
|
288
271
|
index as default
|
|
289
272
|
};
|
|
290
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -5,11 +5,9 @@ export interface TranscriptSegment {
|
|
|
5
5
|
duration: number;
|
|
6
6
|
}
|
|
7
7
|
export interface TranscriptData {
|
|
8
|
-
title: string;
|
|
9
8
|
videoId: string;
|
|
10
|
-
thumbnailUrl: string;
|
|
11
9
|
fullTranscript: string;
|
|
12
10
|
transcriptWithTimeCodes: TranscriptSegment[];
|
|
13
11
|
}
|
|
14
|
-
declare const fetchTranscript: (
|
|
12
|
+
declare const fetchTranscript: (videoId: string) => Promise<TranscriptData>;
|
|
15
13
|
export default fetchTranscript;
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"App-DKY3upWd.js","sources":["../../admin/src/pages/HomePage.tsx","../../admin/src/pages/App.tsx"],"sourcesContent":["import { Main } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nconst HomePage = () => {\n const { formatMessage } = useIntl();\n\n return (\n <Main>\n <h1>Welcome to {formatMessage({ id: getTranslation('plugin.name') })}</h1>\n </Main>\n );\n};\n\nexport { HomePage };\n","import { Page } from '@strapi/strapi/admin';\nimport { Routes, Route } from 'react-router-dom';\n\nimport { HomePage } from './HomePage';\n\nconst App = () => {\n return (\n <Routes>\n <Route index element={<HomePage />} />\n <Route path=\"*\" element={<Page.Error />} />\n </Routes>\n );\n};\n\nexport { App };\n"],"names":["useIntl","jsx","Main","jsxs","getTranslation","Routes","Route","Page"],"mappings":";;;;;;;;AAKA,MAAM,WAAW,MAAM;AACf,QAAA,EAAE,cAAc,IAAIA,kBAAQ;AAGhC,SAAAC,2BAAAA,IAACC,aAAAA,MACC,EAAA,UAAAC,2BAAAA,KAAC,MAAG,EAAA,UAAA;AAAA,IAAA;AAAA,IAAY,cAAc,EAAE,IAAIC,MAAe,eAAA,aAAa,EAAG,CAAA;AAAA,EAAA,EAAA,CAAE,EACvE,CAAA;AAEJ;ACRA,MAAM,MAAM,MAAM;AAChB,yCACGC,uBACC,EAAA,UAAA;AAAA,IAAAJ,+BAACK,eAAAA,SAAM,OAAK,MAAC,SAASL,+BAAC,WAAS,CAAA,GAAI;AAAA,IACpCA,+BAACK,eAAAA,SAAM,MAAK,KAAI,SAAUL,2BAAAA,IAAAM,MAAA,KAAK,OAAL,CAAA,CAAW,EAAI,CAAA;AAAA,EAAA,GAC3C;AAEJ;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"App-DXPFDMBH.mjs","sources":["../../admin/src/pages/HomePage.tsx","../../admin/src/pages/App.tsx"],"sourcesContent":["import { Main } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nconst HomePage = () => {\n const { formatMessage } = useIntl();\n\n return (\n <Main>\n <h1>Welcome to {formatMessage({ id: getTranslation('plugin.name') })}</h1>\n </Main>\n );\n};\n\nexport { HomePage };\n","import { Page } from '@strapi/strapi/admin';\nimport { Routes, Route } from 'react-router-dom';\n\nimport { HomePage } from './HomePage';\n\nconst App = () => {\n return (\n <Routes>\n <Route index element={<HomePage />} />\n <Route path=\"*\" element={<Page.Error />} />\n </Routes>\n );\n};\n\nexport { App };\n"],"names":[],"mappings":";;;;;;AAKA,MAAM,WAAW,MAAM;AACf,QAAA,EAAE,cAAc,IAAI,QAAQ;AAGhC,SAAA,oBAAC,MACC,EAAA,UAAA,qBAAC,MAAG,EAAA,UAAA;AAAA,IAAA;AAAA,IAAY,cAAc,EAAE,IAAI,eAAe,aAAa,EAAG,CAAA;AAAA,EAAA,EAAA,CAAE,EACvE,CAAA;AAEJ;ACRA,MAAM,MAAM,MAAM;AAChB,8BACG,QACC,EAAA,UAAA;AAAA,IAAA,oBAAC,SAAM,OAAK,MAAC,SAAS,oBAAC,WAAS,CAAA,GAAI;AAAA,IACpC,oBAAC,SAAM,MAAK,KAAI,SAAU,oBAAA,KAAK,OAAL,CAAA,CAAW,EAAI,CAAA;AAAA,EAAA,GAC3C;AAEJ;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"en-B4KWt_jN.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"en-Byx4XI2L.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-Cf76FLRe.mjs","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript-strapi-plugin';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAM,OAAO,SAAS;AAE5B,YAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAM,oBAAC,aAAY,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,OAAO,oBAAa;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,OAAA,mBAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-CpWYZFmv.js","sources":["../../admin/src/pluginId.ts","../../admin/src/utils/getTranslation.ts","../../admin/src/components/Initializer.tsx","../../admin/src/components/PluginIcon.tsx","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'yt-transcript-strapi-plugin';\n","import { PLUGIN_ID } from '../pluginId';\n\nconst getTranslation = (id: string) => `${PLUGIN_ID}.${id}`;\n\nexport { getTranslation };\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","import { PuzzlePiece } from '@strapi/icons';\n\nconst PluginIcon = () => <PuzzlePiece />;\n\nexport { PluginIcon };\n","import { getTranslation } from './utils/getTranslation';\nimport { PLUGIN_ID } from './pluginId';\nimport { Initializer } from './components/Initializer';\nimport { PluginIcon } from './components/PluginIcon';\n\nexport default {\n register(app: any) {\n app.addMenuLink({\n to: `plugins/${PLUGIN_ID}`,\n icon: PluginIcon,\n intlLabel: {\n id: `${PLUGIN_ID}.plugin.name`,\n defaultMessage: PLUGIN_ID,\n },\n Component: async () => {\n const { App } = await import('./pages/App');\n\n return App;\n },\n });\n\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n },\n\n async registerTrads(app: any) {\n const { locales } = app;\n\n const importedTranslations = await Promise.all(\n (locales as string[]).map((locale) => {\n return import(`./translations/${locale}.json`)\n .then(({ default: data }) => {\n return {\n data: getTranslation(data),\n locale,\n };\n })\n .catch(() => {\n return {\n data: {},\n locale,\n };\n });\n })\n );\n\n return importedTranslations;\n },\n};\n"],"names":["useRef","useEffect","jsx","PuzzlePiece"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACEzB,MAAM,iBAAiB,CAAC,OAAe,GAAG,SAAS,IAAI,EAAE;ACMzD,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACjD,QAAA,MAAMA,aAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,EAAE;AAEE,SAAA;AACT;ACdA,MAAM,aAAa,MAAMC,2BAAAA,IAACC,MAAY,aAAA,EAAA;ACGtC,MAAe,QAAA;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,YAAY;AAAA,MACd,IAAI,WAAW,SAAS;AAAA,MACxB,MAAM;AAAA,MACN,WAAW;AAAA,QACT,IAAI,GAAG,SAAS;AAAA,QAChB,gBAAgB;AAAA,MAClB;AAAA,MACA,WAAW,YAAY;AACrB,cAAM,EAAE,IAAA,IAAQ,MAAM,QAAA,QAAA,EAAA,KAAA,MAAA,QAAO,mBAAa,CAAA;AAEnC,eAAA;AAAA,MAAA;AAAA,IACT,CACD;AAED,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,KAAU;AACtB,UAAA,EAAE,YAAY;AAEd,UAAA,uBAAuB,MAAM,QAAQ;AAAA,MACxC,QAAqB,IAAI,CAAC,WAAW;AAC7B,eAAA,qCAA+B,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,kBAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA,EACnC,KAAK,CAAC,EAAE,SAAS,WAAW;AACpB,iBAAA;AAAA,YACL,MAAM,eAAe,IAAI;AAAA,YACzB;AAAA,UACF;AAAA,QAAA,CACD,EACA,MAAM,MAAM;AACJ,iBAAA;AAAA,YACL,MAAM,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QAAA,CACD;AAAA,MACJ,CAAA;AAAA,IACH;AAEO,WAAA;AAAA,EAAA;AAEX;;;"}
|
package/dist/admin/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
package/dist/admin/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/server/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData?.title || \"No title found\",\n videoId: transcriptData?.videoId,\n thumbnailUrl: transcriptData?.thumbnailUrl || \"No thumbnail URL found\",\n fullTranscript: transcriptData?.fullTranscript,\n transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Payload:\", payload);\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (identifier: string): Promise<TranscriptData> => {\n console.log('Fetching Transcript - Calling fetchTranscript Utils');\n const { Innertube } = await import('youtubei.js');\n\n console.log('Creating YouTube instance');\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log('Transcript data fetched');\n\n const transcriptWithTimeCodes: TranscriptSegment[] =\n transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n });\n\n console.log('Transcript with time codes generated');\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log('Cleaning thumbnail URL');\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments\n .map((segment) => segment.snippet.text)\n .join(' ');\n\n console.log(fullTranscript, 'full transcript');\n\n console.log('Full transcript generated');\n\n console.log('Getting basic info');\n\n const title = info.basic_info?.title;\n const videoId = info.basic_info?.id;\n\n console.log('Getting thumbnail URL');\n const thumbnailUrl = info?.basic_info?.thumbnail[0]?.url;\n\n console.log('Returning transcript data');\n\n return {\n videoId,\n ...(title ? { title } : { title: 'No title found' }),\n ...(thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: '' }),\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;\n","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript-strapi-plugin') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n\n const test = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript')\n\n console.log('Test:', test);\n\n const transcriptData = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').findFirst({\n filters: { videoId },\n });\n\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","ChatOpenAI","info","PromptTemplate","TokenTextSplitter"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/transcript/index.ts","../../server/src/content-types/index.ts","../../server/src/utils/extract-youtube-id.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../server/src/utils/openai.ts","../../server/src/utils/fetch-transcript.ts","../../server/src/services/service.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","import type { Core } from '@strapi/strapi';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // register phase\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import transcript from './transcript';\n\nexport default {\n transcript,\n};\n\n\n","export function extractYouTubeID(urlOrID: string): string | null {\n // Regular expression for YouTube ID format\n const regExpID = /^[a-zA-Z0-9_-]{11}$/;\n\n // Check if the input is a YouTube ID\n if (regExpID.test(urlOrID)) {\n return urlOrID;\n }\n\n // Regular expression for standard YouTube links\n const regExpStandard = /youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]+)/;\n\n // Regular expression for YouTube Shorts links\n const regExpShorts = /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]+)/;\n\n // Check for standard YouTube link\n const matchStandard = urlOrID.match(regExpStandard);\n if (matchStandard) {\n return matchStandard[1];\n }\n\n // Check for YouTube Shorts link\n const matchShorts = urlOrID.match(regExpShorts);\n if (matchShorts) {\n return matchShorts[1];\n }\n\n // Return null if no match is found\n return null;\n}","import type { Core } from '@strapi/strapi';\nimport { extractYouTubeID } from '../utils/extract-youtube-id';\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(ctx) {\n const videoId = extractYouTubeID(ctx.params.videoId);\n\n if (!videoId) return (ctx.body = { error: 'Invalid YouTube URL or ID', data: null });\n\n console.log(\"Looking for transcript in database\");\n\n const found = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .findTranscript(videoId);\n\n if (found) {\n console.log(\"Transcript found.\");\n return (ctx.body = { data: found });\n }\n\n console.log(\"Transcript not found. Fetching new transcript.\");\n\n const transcriptData = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .getTranscript(videoId);\n\n console.log(\"New transcript fetched.\");\n\n const readableTranscript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .generateHumanReadableTranscript(transcriptData.fullTranscript);\n\n console.log(\"Human readable transcript generated.\");\n\n const payload = {\n title: transcriptData?.title || \"No title found\",\n videoId: transcriptData?.videoId,\n thumbnailUrl: transcriptData?.thumbnailUrl || \"No thumbnail URL found\",\n fullTranscript: transcriptData?.fullTranscript,\n transcriptWithTimeCodes: transcriptData?.transcriptWithTimeCodes,\n readableTranscript: readableTranscript,\n };\n\n console.log(\"Payload:\", payload);\n\n console.log(\"Saving new transcript to database.\");\n\n const transcript = await strapi\n .plugin('yt-transcript-strapi-plugin')\n .service('service')\n .saveTranscript(payload);\n\n ctx.body = { data: transcript };\n },\n});\n\nexport default controller;\n","import controller from './controller';\n\nexport default {\n controller,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","export default [\n {\n method: 'GET',\n path: '/yt-transcript/:videoId',\n handler: 'controller.getTranscript',\n config: { \n policies: [], \n }, \n },\n];","\"use strict\";\n\nimport contentApi from \"./content-api\";\nimport admin from \"./admin\";\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n};","import { ChatOpenAI } from \"@langchain/openai\";\n\ninterface InitializeModelProps {\n openAIApiKey: string;\n model: string;\n temp: number;\n maxTokens?: number;\n}\n\nexport async function initializeModel({\n openAIApiKey,\n model,\n temp,\n}: InitializeModelProps) {\n return new ChatOpenAI({\n temperature: temp,\n openAIApiKey: openAIApiKey,\n modelName: model,\n maxTokens: 1000,\n });\n}","export interface TranscriptSegment {\n text: string;\n start: number;\n end: number;\n duration: number;\n}\n\nexport interface TranscriptData {\n title: string;\n videoId: string;\n thumbnailUrl: string;\n fullTranscript: string;\n transcriptWithTimeCodes: TranscriptSegment[];\n}\n\nconst fetchTranscript = async (identifier: string): Promise<TranscriptData> => {\n console.log('Fetching Transcript - Calling fetchTranscript Utils');\n const { Innertube } = await import('youtubei.js');\n\n console.log('Creating YouTube instance');\n\n const youtube = await Innertube.create({\n lang: 'en',\n location: 'US',\n retrieve_player: false,\n });\n\n try {\n const info = await youtube.getInfo(identifier);\n const transcriptData = await info.getTranscript();\n\n console.log('Transcript data fetched');\n\n const transcriptWithTimeCodes: TranscriptSegment[] =\n transcriptData?.transcript?.content?.body?.initial_segments.map((segment) => {\n const segmentDuration = Number(segment.end_ms) - Number(segment.start_ms);\n return {\n text: segment.snippet.text,\n start: Number(segment.start_ms),\n end: Number(segment.end_ms),\n duration: segmentDuration,\n };\n });\n\n console.log('Transcript with time codes generated');\n\n function cleanImageUrl(url) {\n return url.split('?')[0];\n }\n\n console.log('Cleaning thumbnail URL');\n\n const fullTranscript = transcriptData?.transcript?.content?.body?.initial_segments\n .map((segment) => segment.snippet.text)\n .join(' ');\n\n console.log(fullTranscript, 'full transcript');\n\n console.log('Full transcript generated');\n\n console.log('Getting basic info');\n\n const title = info.basic_info?.title;\n const videoId = info.basic_info?.id;\n\n console.log('Getting thumbnail URL');\n const thumbnailUrl = info?.basic_info?.thumbnail[0]?.url;\n\n console.log('Returning transcript data');\n\n return {\n videoId,\n ...(title ? { title } : { title: 'No title found' }),\n ...(thumbnailUrl ? { thumbnailUrl: cleanImageUrl(thumbnailUrl) } : { thumbnailUrl: '' }),\n fullTranscript,\n transcriptWithTimeCodes,\n };\n } catch (error) {\n console.error('Error fetching transcript:', error);\n throw error;\n }\n};\n\nexport default fetchTranscript;\n","import type { Core } from '@strapi/strapi';\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { TokenTextSplitter } from \"@langchain/textsplitters\";\nimport { PromptTemplate } from \"@langchain/core/prompts\";\n\nimport { initializeModel } from \"../utils/openai\";\nimport fetchTranscript from '../utils/fetch-transcript';\n\ninterface YTTranscriptConfig {\n openAIApiKey: string;\n model?: string;\n temp?: number;\n maxTokens?: number;\n}\n\nasync function processTextChunks(chunks: string[], model: ChatOpenAI) {\n const punctuationPrompt = PromptTemplate.fromTemplate(\n \"Add proper punctuation and capitalization to the following text chunk:\\n\\n{chunk}\"\n );\n const punctuationChain = punctuationPrompt.pipe(model);\n\n const processedChunks = await Promise.all(\n chunks.map(async (chunk) => {\n const result = await punctuationChain.invoke({ chunk });\n return result.content as string;\n })\n );\n\n return processedChunks.join(\" \");\n}\n\nexport async function generateModifiedTranscript (rawTranscript: string) {\n const pluginSettings = await strapi.config.get('plugin::yt-transcript-strapi-plugin') as YTTranscriptConfig; \n \n if (!pluginSettings.openAIApiKey || !pluginSettings.model || !pluginSettings.temp || !pluginSettings.maxTokens) {\n throw new Error('Missing required configuration for YTTranscript');\n }\n\n const chatModel = await initializeModel({\n openAIApiKey: pluginSettings.openAIApiKey,\n model: pluginSettings.model,\n temp: pluginSettings.temp,\n maxTokens: pluginSettings.maxTokens,\n });\n\n const splitter = new TokenTextSplitter({\n chunkSize: 1000,\n chunkOverlap: 200,\n });\n\n const transcriptChunks = await splitter.createDocuments([rawTranscript]);\n const chunkTexts = transcriptChunks.map(chunk => chunk.pageContent);\n const modifiedTranscript = await processTextChunks(chunkTexts, chatModel);\n return modifiedTranscript;\n}\n\nconst service = ({ strapi }: { strapi: Core.Strapi }) => ({\n async getTranscript(identifier: string) {\n console.log(\"Fetching Transcript - Calling fetchTranscript Service\");\n const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;\n const isValid = youtubeIdRegex.test(identifier);\n if (!isValid) return { error: 'Invalid video ID', data: null };\n const transcriptData = await fetchTranscript(identifier);\n return transcriptData;\n },\n\n async saveTranscript(payload) {\n // console.log('Saving transcript:', payload);\n return await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').create({\n data: payload,\n });\n },\n\n async findTranscript(videoId) {\n console.log('Finding transcript for videoId:', videoId);\n\n const test = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript')\n\n console.log('Test:', test);\n\n const transcriptData = await strapi.documents('plugin::yt-transcript-strapi-plugin.transcript').findFirst({\n filters: { videoId },\n });\n\n\n console.log('Transcript found:', transcriptData?.title, 'found');\n\n if (!transcriptData) return null;\n return transcriptData;\n },\n\n async generateHumanReadableTranscript(transcript) {\n console.log('Generating human readable transcript:');\n const modifiedTranscript = await generateModifiedTranscript(transcript);\n return modifiedTranscript;\n },\n});\n\nexport default service;\n","import service from './service';\n\nexport default {\n service,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["strapi","transcript","info"],"mappings":"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"}
|