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.
@@ -20,4 +20,3 @@ const App = () => {
20
20
  ] });
21
21
  };
22
22
  exports.App = App;
23
- //# sourceMappingURL=App-DKY3upWd.js.map
@@ -20,4 +20,3 @@ const App = () => {
20
20
  export {
21
21
  App
22
22
  };
23
- //# sourceMappingURL=App-DXPFDMBH.mjs.map
@@ -2,4 +2,3 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const en = {};
4
4
  exports.default = en;
5
- //# sourceMappingURL=en-B4KWt_jN.js.map
@@ -2,4 +2,3 @@ const en = {};
2
2
  export {
3
3
  en as default
4
4
  };
5
- //# sourceMappingURL=en-Byx4XI2L.mjs.map
@@ -72,4 +72,3 @@ export {
72
72
  getTranslation as g,
73
73
  index as i
74
74
  };
75
- //# sourceMappingURL=index-Cf76FLRe.mjs.map
@@ -71,4 +71,3 @@ const index = {
71
71
  };
72
72
  exports.getTranslation = getTranslation;
73
73
  exports.index = index;
74
- //# sourceMappingURL=index-CpWYZFmv.js.map
@@ -1,4 +1,3 @@
1
1
  "use strict";
2
2
  const index = require("../_chunks/index-CpWYZFmv.js");
3
3
  module.exports = index.index;
4
- //# sourceMappingURL=index.js.map
@@ -2,4 +2,3 @@ import { i } from "../_chunks/index-Cf76FLRe.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
5
- //# sourceMappingURL=index.mjs.map
@@ -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 (identifier) => {
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
- let cleanImageUrl = function(url) {
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
@@ -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 (identifier) => {
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
- let cleanImageUrl = function(url) {
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
@@ -26,9 +26,6 @@ declare const _default: {
26
26
  videoId: {
27
27
  type: string;
28
28
  };
29
- thumbnailUrl: {
30
- type: string;
31
- };
32
29
  fullTranscript: {
33
30
  type: string;
34
31
  };
@@ -25,9 +25,6 @@ declare const _default: {
25
25
  videoId: {
26
26
  type: string;
27
27
  };
28
- thumbnailUrl: {
29
- type: string;
30
- };
31
28
  fullTranscript: {
32
29
  type: string;
33
30
  };
@@ -90,9 +90,6 @@ declare const _default: {
90
90
  videoId: {
91
91
  type: string;
92
92
  };
93
- thumbnailUrl: {
94
- type: string;
95
- };
96
93
  fullTranscript: {
97
94
  type: string;
98
95
  };
@@ -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: (identifier: string) => Promise<TranscriptData>;
12
+ declare const fetchTranscript: (videoId: string) => Promise<TranscriptData>;
15
13
  export default fetchTranscript;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.10",
2
+ "version": "0.0.12",
3
3
  "keywords": [
4
4
  "yt-transcript-strapi-plugin",
5
5
  "youtube",
@@ -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;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -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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"}