podverse-external-services 5.1.1-alpha.4 → 5.1.1-alpha.6

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.
@@ -10,11 +10,15 @@ export declare class PodcastIndexService {
10
10
  secretKey: string;
11
11
  constructor({ authKey, baseUrl, secretKey }: Constructor);
12
12
  podcastIndexAPIRequest: (url: string, config?: any) => Promise<any>;
13
- getRecentlyUpdatedData: () => Promise<any[]>;
14
- getPodcastByGuid: (podcastGuid: string) => Promise<PodcastByGuidResponse | null>;
15
- getValueTagEnabledPodcastIdsRecursively: (accumulatedPodcastIndexIds: number[], startAt?: number) => Promise<number[]>;
16
- getValueTagEnabledPodcastIds: () => Promise<number[]>;
17
- downloadAndExtractCSV: () => Promise<any[]>;
13
+ deadFeedsDownloadAndExtractCSV: () => Promise<any[]>;
14
+ podcastGetByGuid: (podcastGuid: string) => Promise<PodcastByGuidResponse | null>;
15
+ recentGetData: () => Promise<any[]>;
16
+ trendingGetPodcasts: (max?: number, since?: number, lang?: string, cat?: string) => Promise<{
17
+ feeds: any[];
18
+ nextSince?: number;
19
+ }>;
20
+ valueGetByPodcastIds: () => Promise<number[]>;
21
+ valueGetByPodcastIdsRecursively: (accumulatedPodcastIndexIds: number[], startAt?: number) => Promise<number[]>;
18
22
  }
19
23
  export {};
20
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/podcast-index/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AASD,qBAAa,mBAAmB;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;gBAEZ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,WAAW;IAMzD,sBAAsB,GAAU,KAAK,MAAM,EAAE,SAAS,GAAG,kBAkDxD;IAED,sBAAsB,uBA6BrB;IAED,gBAAgB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAYpF;IAED,uCAAuC,GACrC,4BAA4B,MAAM,EAAE,EAAE,gBAAW,KAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAatE;IAED,4BAA4B,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAMzD;IAED,qBAAqB,QAAa,OAAO,CAAC,GAAG,EAAE,CAAC,CAwC/C;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/podcast-index/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AASD,qBAAa,mBAAmB;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;gBAEZ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,WAAW;IAQzD,sBAAsB,GAAU,KAAK,MAAM,EAAE,SAAS,GAAG,kBA0BxD;IAID,8BAA8B,QAAa,OAAO,CAAC,GAAG,EAAE,CAAC,CAwCxD;IAID,gBAAgB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAYpF;IAID,aAAa,uBA6BZ;IAID,mBAAmB,GACjB,MAAK,MAAW,EAChB,QAAQ,MAAM,EACd,OAAO,MAAM,EACb,MAAM,MAAM,KACX,OAAO,CAAC;QAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAoB/C;IAID,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAMjD;IAED,+BAA+B,GAC7B,4BAA4B,MAAM,EAAE,EAAE,gBAAW,KAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAatE;CACF"}
@@ -28,39 +28,17 @@ const config_1 = require("@external-services/config");
28
28
  */
29
29
  class PodcastIndexService {
30
30
  constructor({ authKey, baseUrl, secretKey }) {
31
+ // Request handler
31
32
  this.podcastIndexAPIRequest = (url, config) => __awaiter(this, void 0, void 0, function* () {
32
33
  var _a, _b, _c;
33
34
  const apiHeaderTime = Math.floor(Date.now() / 1000);
34
35
  const hash = (0, sha1_1.default)(this.authKey + this.secretKey + apiHeaderTime).toString(enc_hex_1.default);
35
- console.log('[PodcastIndex] Request details', {
36
- url,
37
- apiHeaderTime,
38
- authKey: this.authKey,
39
- baseUrl: this.baseUrl,
40
- secretKeyPresent: !!this.secretKey,
41
- headers: {
42
- 'X-Auth-Key': this.authKey,
43
- 'X-Auth-Date': apiHeaderTime,
44
- Authorization: hash
45
- },
46
- config
47
- });
48
- // Log system time for drift debugging
49
- console.log('[PodcastIndex] System time (UTC)', {
50
- iso: new Date().toISOString(),
51
- epoch: Math.floor(Date.now() / 1000)
52
- });
53
36
  try {
54
37
  const response = yield (0, podverse_helpers_1.request)(url, Object.assign({ headers: {
55
38
  'X-Auth-Key': this.authKey,
56
39
  'X-Auth-Date': apiHeaderTime,
57
40
  Authorization: hash
58
41
  } }, config));
59
- console.log('[PodcastIndex] Response received', {
60
- status: response === null || response === void 0 ? void 0 : response.status,
61
- statusText: response === null || response === void 0 ? void 0 : response.statusText,
62
- dataKeys: (response === null || response === void 0 ? void 0 : response.data) ? Object.keys(response.data) : undefined
63
- });
64
42
  return response;
65
43
  }
66
44
  catch (error) {
@@ -75,8 +53,55 @@ class PodcastIndexService {
75
53
  throw error;
76
54
  }
77
55
  });
78
- this.getRecentlyUpdatedData = () => __awaiter(this, void 0, void 0, function* () {
79
- podverse_helpers_1.logger.info('getRecentlyUpdatedData beginning...');
56
+ // Dead Feeds
57
+ this.deadFeedsDownloadAndExtractCSV = () => __awaiter(this, void 0, void 0, function* () {
58
+ const url = 'https://public.podcastindex.org/podcastindex_dead_feeds.csv';
59
+ const tmpDir = path_1.default.join(__dirname, 'tmp');
60
+ const filePath = path_1.default.join(tmpDir, 'podcastindex_dead_feeds.csv');
61
+ if (!fs_1.default.existsSync(tmpDir)) {
62
+ fs_1.default.mkdirSync(tmpDir);
63
+ }
64
+ const data = yield this.podcastIndexAPIRequest(url, { responseType: 'stream' });
65
+ const writer = fs_1.default.createWriteStream(filePath);
66
+ data.pipe(writer);
67
+ yield new Promise((resolve, reject) => {
68
+ writer.on('finish', () => resolve());
69
+ writer.on('error', reject);
70
+ });
71
+ const results = [];
72
+ yield new Promise((resolve, reject) => {
73
+ fs_1.default.createReadStream(filePath)
74
+ .pipe((0, csv_parser_1.default)())
75
+ .on('data', (data) => results.push(data))
76
+ .on('end', resolve)
77
+ .on('error', reject);
78
+ });
79
+ fs_1.default.unlinkSync(filePath);
80
+ const parsedResults = results.map((row) => {
81
+ const [id, duplicateOf] = Object.values(row).map((value) => value.trim());
82
+ return {
83
+ podcast_index_id: parseInt(id, 10),
84
+ duplicateOf: duplicateOf ? parseInt(duplicateOf, 10) : null
85
+ };
86
+ });
87
+ return parsedResults;
88
+ });
89
+ // Podcast
90
+ this.podcastGetByGuid = (podcastGuid) => __awaiter(this, void 0, void 0, function* () {
91
+ const url = `${this.baseUrl}/podcasts/byguid?guid=${podcastGuid}`;
92
+ let podcastIndexPodcast = null;
93
+ try {
94
+ const data = yield this.podcastIndexAPIRequest(url);
95
+ podcastIndexPodcast = data;
96
+ }
97
+ catch (error) {
98
+ // assume a 404
99
+ }
100
+ return podcastIndexPodcast || null;
101
+ });
102
+ // Recent
103
+ this.recentGetData = () => __awaiter(this, void 0, void 0, function* () {
104
+ podverse_helpers_1.logger.info('recentGetData beginning...');
80
105
  const currentTimeInSeconds = Math.floor(Date.now() / 1000);
81
106
  const sinceRange = config_1.config.podcastIndex.recentlyUpdatedDataInterval;
82
107
  const sinceTimeInSeconds = currentTimeInSeconds - sinceRange;
@@ -100,67 +125,44 @@ class PodcastIndexService {
100
125
  });
101
126
  return fetchData(sinceTimeInSeconds);
102
127
  });
103
- this.getPodcastByGuid = (podcastGuid) => __awaiter(this, void 0, void 0, function* () {
104
- const url = `${this.baseUrl}/podcasts/byguid?guid=${podcastGuid}`;
105
- let podcastIndexPodcast = null;
106
- try {
107
- const data = yield this.podcastIndexAPIRequest(url);
108
- podcastIndexPodcast = data;
128
+ // Trending
129
+ this.trendingGetPodcasts = (...args_1) => __awaiter(this, [...args_1], void 0, function* (max = 25, since, lang, cat) {
130
+ const safeMax = Math.min(max, 1000);
131
+ let url = `${this.baseUrl}/podcasts/trending?max=${safeMax}`;
132
+ if (since) {
133
+ url += `&since=${since}`;
109
134
  }
110
- catch (error) {
111
- // assume a 404
135
+ if (lang) {
136
+ url += `&lang=${encodeURIComponent(lang)}`;
112
137
  }
113
- return podcastIndexPodcast || null;
138
+ if (cat) {
139
+ url += `&cat=${encodeURIComponent(cat)}`;
140
+ }
141
+ podverse_helpers_1.logger.info(`[PodcastIndex] Fetching trending feeds (max: ${safeMax}, since: ${since}, lang: ${lang}, cat: ${cat})`);
142
+ const response = yield this.podcastIndexAPIRequest(url);
143
+ return {
144
+ feeds: response.feeds || [],
145
+ nextSince: response.nextSince
146
+ };
147
+ });
148
+ // Value
149
+ this.valueGetByPodcastIds = () => __awaiter(this, void 0, void 0, function* () {
150
+ const accumulatedPodcastIndexIds = [];
151
+ const nextStartAt = 1;
152
+ const podcastIndexIds = yield this.valueGetByPodcastIdsRecursively(accumulatedPodcastIndexIds, nextStartAt);
153
+ return podcastIndexIds;
114
154
  });
115
- this.getValueTagEnabledPodcastIdsRecursively = (accumulatedPodcastIndexIds_1, ...args_1) => __awaiter(this, [accumulatedPodcastIndexIds_1, ...args_1], void 0, function* (accumulatedPodcastIndexIds, startAt = 1) {
155
+ this.valueGetByPodcastIdsRecursively = (accumulatedPodcastIndexIds_1, ...args_1) => __awaiter(this, [accumulatedPodcastIndexIds_1, ...args_1], void 0, function* (accumulatedPodcastIndexIds, startAt = 1) {
116
156
  const url = `${this.baseUrl}/podcasts/bytag?podcast-valueTimeSplit=true&max=5000&start_at=${startAt}`;
117
157
  const data = yield this.podcastIndexAPIRequest(url);
118
158
  for (const feed of data.feeds) {
119
159
  accumulatedPodcastIndexIds.push(feed.id);
120
160
  }
121
161
  if (data.nextStartAt) {
122
- return yield this.getValueTagEnabledPodcastIdsRecursively(accumulatedPodcastIndexIds, data.nextStartAt);
162
+ return yield this.valueGetByPodcastIdsRecursively(accumulatedPodcastIndexIds, data.nextStartAt);
123
163
  }
124
164
  return accumulatedPodcastIndexIds;
125
165
  });
126
- this.getValueTagEnabledPodcastIds = () => __awaiter(this, void 0, void 0, function* () {
127
- const accumulatedPodcastIndexIds = [];
128
- const nextStartAt = 1;
129
- const podcastIndexIds = yield this.getValueTagEnabledPodcastIdsRecursively(accumulatedPodcastIndexIds, nextStartAt);
130
- return podcastIndexIds;
131
- });
132
- this.downloadAndExtractCSV = () => __awaiter(this, void 0, void 0, function* () {
133
- const url = 'https://public.podcastindex.org/podcastindex_dead_feeds.csv';
134
- const tmpDir = path_1.default.join(__dirname, 'tmp');
135
- const filePath = path_1.default.join(tmpDir, 'podcastindex_dead_feeds.csv');
136
- if (!fs_1.default.existsSync(tmpDir)) {
137
- fs_1.default.mkdirSync(tmpDir);
138
- }
139
- const data = yield this.podcastIndexAPIRequest(url, { responseType: 'stream' });
140
- const writer = fs_1.default.createWriteStream(filePath);
141
- data.pipe(writer);
142
- yield new Promise((resolve, reject) => {
143
- writer.on('finish', () => resolve());
144
- writer.on('error', reject);
145
- });
146
- const results = [];
147
- yield new Promise((resolve, reject) => {
148
- fs_1.default.createReadStream(filePath)
149
- .pipe((0, csv_parser_1.default)())
150
- .on('data', (data) => results.push(data))
151
- .on('end', resolve)
152
- .on('error', reject);
153
- });
154
- fs_1.default.unlinkSync(filePath);
155
- const parsedResults = results.map((row) => {
156
- const [id, duplicateOf] = Object.values(row).map((value) => value.trim());
157
- return {
158
- podcast_index_id: parseInt(id, 10),
159
- duplicateOf: duplicateOf ? parseInt(duplicateOf, 10) : null
160
- };
161
- });
162
- return parsedResults;
163
- });
164
166
  this.authKey = authKey;
165
167
  this.baseUrl = baseUrl;
166
168
  this.secretKey = secretKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "podverse-external-services",
3
- "version": "5.1.1-alpha.4",
3
+ "version": "5.1.1-alpha.6",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",