patreon-dl 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/dist/downloaders/PostDownloader.d.ts.map +1 -1
- package/dist/downloaders/PostDownloader.js +20 -9
- package/dist/downloaders/PostDownloader.js.map +1 -1
- package/dist/downloaders/task/DownloadTaskFactory.d.ts.map +1 -1
- package/dist/downloaders/task/DownloadTaskFactory.js +93 -99
- package/dist/downloaders/task/DownloadTaskFactory.js.map +1 -1
- package/dist/entities/Downloadable.js +1 -1
- package/dist/entities/Downloadable.js.map +1 -1
- package/dist/entities/Post.d.ts +0 -1
- package/dist/entities/Post.d.ts.map +1 -1
- package/dist/entities/Post.js.map +1 -1
- package/dist/utils/FllenameResolver.d.ts +1 -1
- package/dist/utils/FllenameResolver.d.ts.map +1 -1
- package/dist/utils/FllenameResolver.js +9 -7
- package/dist/utils/FllenameResolver.js.map +1 -1
- package/dist/utils/MediaFilenameResolver.d.ts.map +1 -1
- package/dist/utils/MediaFilenameResolver.js +6 -3
- package/dist/utils/MediaFilenameResolver.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,7 +23,9 @@ You can run `patreon-dl` from the command-line or [use it as a library](./docs/L
|
|
|
23
23
|
|
|
24
24
|
### Limitations
|
|
25
25
|
|
|
26
|
-
- Embedded links are not followed; only info about the embed is saved.
|
|
26
|
+
- Embedded links are not followed; only info about the embed is saved. Exception:
|
|
27
|
+
- YouTube video link - in which case the video is downloaded; or
|
|
28
|
+
- An external downloader is configured for the link provider.
|
|
27
29
|
|
|
28
30
|
### FFmpeg dependency
|
|
29
31
|
|
|
@@ -33,9 +35,9 @@ You can run `patreon-dl` from the command-line or [use it as a library](./docs/L
|
|
|
33
35
|
|
|
34
36
|
Not all video downloads require FFmpeg, but you should have it installed on your system anyway.
|
|
35
37
|
|
|
36
|
-
### Embedded YouTube videos - Premium access
|
|
38
|
+
### Embedded YouTube videos / links - Premium access
|
|
37
39
|
|
|
38
|
-
`patreon-dl` supports downloading embedded YouTube videos. In addition, if you have a YouTube Premium subscription, you can connect `patreon-dl` to your account and download videos at qualities available only to Premium accounts (e.g. '1080p Premium'). For CLI users, you would configure `patreon-dl` as follows:
|
|
40
|
+
`patreon-dl` supports downloading embedded YouTube videos or from embedded YouTube video links. In addition, if you have a YouTube Premium subscription, you can connect `patreon-dl` to your account and download videos at qualities available only to Premium accounts (e.g. '1080p Premium'). For CLI users, you would configure `patreon-dl` as follows:
|
|
39
41
|
|
|
40
42
|
```
|
|
41
43
|
$ patreon-dl --configure-youtube
|
|
@@ -43,9 +45,9 @@ $ patreon-dl --configure-youtube
|
|
|
43
45
|
|
|
44
46
|
> ...or you may just refer to the next section on how to download enhanecd-quality videos without a Premium account.
|
|
45
47
|
|
|
46
|
-
### Embedded videos - external downloader
|
|
48
|
+
### Embedded videos / links - external downloader
|
|
47
49
|
|
|
48
|
-
You can specify external programs to download embedded videos. For YouTube videos, this will replace the built-in downloader. See the [example config](./example-embed.conf) on how to do this.
|
|
50
|
+
You can specify external programs to download embedded videos or from embedded links. For YouTube videos, this will replace the built-in downloader. See the [example config](./example-embed.conf) on how to do this.
|
|
49
51
|
|
|
50
52
|
> The example config utilizes [yt-dlp](https://github.com/yt-dlp/yt-dlp), a popular program capable of downloading YouTube and Vimeo content. As of current release, `yt-dlp` is also able to download Premium-quality YouTube videos without a Premium account.
|
|
51
53
|
|
|
@@ -219,6 +221,11 @@ Note that you can override an option from a configuration file with one provided
|
|
|
219
221
|
|
|
220
222
|
## Changelog
|
|
221
223
|
|
|
224
|
+
v2.2.0
|
|
225
|
+
- Widen scope of external downloaders to any type of embed (previously only works for video embeds) ([#51](https://github.com/patrickkfkan/patreon-dl/issues/51))
|
|
226
|
+
- YouTube downloading now covers embedded YT links
|
|
227
|
+
- Fix attachment filenames sometimes have wrong extension
|
|
228
|
+
|
|
222
229
|
v2.1.1
|
|
223
230
|
- Fix multiple abort signal listeners triggering warning ([#48](https://github.com/patrickkfkan/patreon-dl/issues/48))
|
|
224
231
|
- Fix YouTube embeds failing to download due to YT changes ([#50](https://github.com/patrickkfkan/patreon-dl/issues/50))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostDownloader.d.ts","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAyB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGhG,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAShD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,IAAI,CAAC;;IAE1D,MAAM,CAAC,OAAO,SAAW;IAEzB,IAAI,SAAoB;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoe9C,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"PostDownloader.d.ts","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"AACA,OAAO,UAAU,EAAE,EAAyB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGhG,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAShD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,IAAI,CAAC;;IAE1D,MAAM,CAAC,OAAO,SAAW;IAEzB,IAAI,SAAoB;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoe9C,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW;CAyIzC"}
|
|
@@ -178,7 +178,7 @@ class PostDownloader extends Downloader {
|
|
|
178
178
|
const hasAttachments = post.attachments.length > 0;
|
|
179
179
|
const hasAudio = !!post.audio || !!post.audioPreview;
|
|
180
180
|
const hasImages = post.images.length > 0;
|
|
181
|
-
const hasVideo = !!post.video || !!post.videoPreview || !!(post.embed && post.embed.type === 'videoEmbed');
|
|
181
|
+
const hasVideo = !!post.video || !!post.videoPreview || !!(post.embed && (post.embed.type === 'videoEmbed' || isYouTubeEmbed(post.embed)));
|
|
182
182
|
let skip = false;
|
|
183
183
|
if (postsWithMediaType === 'none') {
|
|
184
184
|
skip = hasAttachments || hasAudio || hasImages || hasVideo;
|
|
@@ -506,6 +506,24 @@ _PostDownloader_startPromise = new WeakMap(), _PostDownloader_instances = new We
|
|
|
506
506
|
}
|
|
507
507
|
return incContent.includes(mediaType);
|
|
508
508
|
};
|
|
509
|
+
const __getEmbedTask = () => {
|
|
510
|
+
if (!post.embed) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
const hasEmbedDownloader = DownloadTaskFactory.findEmbedDownloader(this.config.embedDownloaders, post.embed.provider);
|
|
514
|
+
const isDownloadableVideo = isYouTubeEmbed(post.embed) || (post.embed.type === 'videoEmbed' && hasEmbedDownloader);
|
|
515
|
+
const isDownloadableOther = !isYouTubeEmbed(post.embed) && post.embed.type !== 'videoEmbed' && hasEmbedDownloader;
|
|
516
|
+
if ((isDownloadableVideo && __incContent('video')) || isDownloadableOther) {
|
|
517
|
+
const embedType = post.embed.type === 'videoEmbed' ? ' video' : post.embed.type === 'linkEmbed' ? ' link' : '';
|
|
518
|
+
return {
|
|
519
|
+
target: [post.embed],
|
|
520
|
+
targetName: `post #${post.id} -> embedded ${post.embed.provider}${embedType}`,
|
|
521
|
+
destDir: postDirs.embed,
|
|
522
|
+
fileExistsAction: this.config.fileExistsAction.content
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
return null;
|
|
526
|
+
};
|
|
509
527
|
const batchResult = this.createDownloadTaskBatch(`Post #${post.id} (${post.title})`, signal, __incPreview('audio') && post.audioPreview ? {
|
|
510
528
|
target: [post.audioPreview],
|
|
511
529
|
targetName: `post #${post.id} -> audio preview`,
|
|
@@ -546,14 +564,7 @@ _PostDownloader_startPromise = new WeakMap(), _PostDownloader_instances = new We
|
|
|
546
564
|
targetName: `post #${post.id} -> attachments`,
|
|
547
565
|
destDir: postDirs.attachments,
|
|
548
566
|
fileExistsAction: this.config.fileExistsAction.content
|
|
549
|
-
} : null,
|
|
550
|
-
(isYouTubeEmbed(post.embed) || DownloadTaskFactory.findEmbedDownloader(this.config.embedDownloaders, post.embed.provider)) ?
|
|
551
|
-
{
|
|
552
|
-
target: [post.embed],
|
|
553
|
-
targetName: `post #${post.id} -> embedded ${post.embed.provider} video`,
|
|
554
|
-
destDir: postDirs.embed,
|
|
555
|
-
fileExistsAction: this.config.fileExistsAction.content
|
|
556
|
-
} : null);
|
|
567
|
+
} : null, __getEmbedTask());
|
|
557
568
|
return batchResult;
|
|
558
569
|
};
|
|
559
570
|
PostDownloader.version = '1.1.1';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostDownloader.js","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import URLHelper from '../utils/URLHelper.js';\nimport Downloader, { type DownloaderConfig, type DownloaderStartParams } from './Downloader.js';\nimport type DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport PostParser from '../parsers/PostParser.js';\nimport { type Post } from '../entities/Post.js';\nimport { type Downloadable, isYouTubeEmbed } from '../entities/Downloadable.js';\nimport StatusCache from './cache/StatusCache.js';\nimport { generatePostEmbedSummary, generatePostSummary } from './templates/PostInfo.js';\nimport path from 'path';\nimport { TargetSkipReason } from './DownloaderEvent.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport PostsFetcher from './PostsFetcher.js';\n\nexport default class PostDownloader extends Downloader<Post> {\n\n static version = '1.1.1';\n\n name = 'PostDownloader';\n\n #startPromise: Promise<void> | null = null;\n\n start(params?: DownloaderStartParams): Promise<void> {\n\n if (this.#startPromise) {\n throw Error('Downloader already running');\n }\n\n this.#startPromise = new Promise<void>((resolve) => {\n void (async () => {\n const { signal } = params || {};\n const postFetch = this.config.postFetch;\n let batch: DownloadTaskBatch | null = null;\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n const abortHandler = () => {\n void (async () => {\n this.log('info', 'Abort signal received');\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n \n if (postFetch.type === 'byUser') {\n this.log('info', `Targeting posts by '${postFetch.vanity}'`);\n }\n else if (postFetch.type === 'byUserId') {\n this.log('info', `Targeting posts by user #${postFetch.userId}`);\n }\n else if (postFetch.type === 'byCollection') {\n this.log('info', `Targeting posts in collection #${postFetch.collectionId}`);\n }\n else { // Single\n this.log('info', `Targeting post #${postFetch.postId}`);\n }\n if (this.#isFetchingMultiplePosts(postFetch) && postFetch.filters) {\n const filterStr = Object.entries(postFetch.filters).map(([ key, value ]) => `${key}=${value}`).join('; ');\n if (filterStr) {\n this.log('info', `Filters: ${filterStr}`);\n }\n }\n \n // Step 1: Get posts (if by user) or target post\n const postsFetcher = new PostsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n postsFetcher.on('statusChange', ({current}) => {\n if (current.status === 'running') {\n this.emit('fetchBegin', { targetType: postsFetcher.getTargetType() });\n }\n });\n postsFetcher.begin();\n \n // Step 2: download posts in each fetched collection\n let downloaded = 0;\n let skippedUnviewable = 0;\n let skippedRedundant = 0;\n let skippedUnmetMediaTypeCriteria = 0;\n let skippedNotInTier = 0;\n let skippedPublishDateOutOfRange = 0;\n let campaignSaved = false;\n const postsParser = new PostParser(this.logger);\n while (postsFetcher.hasNext()) {\n const { collection, aborted, error } = await postsFetcher.next();\n if (!collection || aborted) {\n break;\n }\n if (!collection && error) {\n this.emit('end', { aborted: false, error, message: 'PostsFetcher error' });\n resolve();\n return;\n }\n if (!campaignSaved && collection.posts[0]?.campaign) {\n await this.saveCampaignInfo(collection.posts[0].campaign, signal);\n campaignSaved = true;\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n }\n \n for (const _post of collection.posts) {\n \n let post = _post;\n \n if (this.#isFetchingMultiplePosts(postFetch)) {\n // Refresh to ensure media links have not expired\n this.log('debug', `Refresh post #${_post.id}`);\n const postURL = URLHelper.constructPostsAPIURL({ postId: _post.id });\n const { json } = await this.commonFetchAPI(postURL, signal);\n let refreshed: Post | null = null;\n if (json) {\n refreshed = postsParser.parsePostsAPIResponse(json, postURL).posts[0] || null;\n if (!refreshed) {\n this.log('warn', `Refreshed post #${_post.id} but got empty value - going to use existing data`);\n }\n else if (refreshed.id !== _post.id) {\n this.log('warn', `Refreshed post #${_post.id} but ID mismatch - going to use existing data`);\n refreshed = null;\n }\n }\n else if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n else {\n this.log('warn', `Failed to refresh post #${_post.id} - going to use existing data`);\n }\n if (refreshed) {\n this.log('debug', `Use refreshed post data #${refreshed.id}`);\n post = refreshed;\n }\n }\n \n this.emit('targetBegin', { target: post });\n \n // Step 4.1: post directories\n const postDirs = this.fsHelper.getPostDirs(post);\n this.log('debug', 'Post directories:', postDirs);\n \n // Step 4.2: Check with status cache\n const statusCache = StatusCache.getInstance(this.config, postDirs.statusCache, this.logger);\n if (statusCache.validate(post, postDirs.root, this.config)) {\n this.log('info', `Skipped downloading post #${post.id}: already downloaded and nothing has changed since last download`);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.AlreadyDownloaded,\n skipMessage: 'Target already downloaded and nothing has changed since last download'\n });\n skippedRedundant++;\n continue;\n }\n \n this.log('info', `Download post #${post.id} (${post.title})`);\n \n // Step 4.3: Check whether we should download post\n // -- 4.3.1: Viewability\n if (!post.isViewable) {\n if (this.config.include.lockedContent) {\n this.log('warn', `Post #${post.id} is not viewable by current user`);\n }\n else {\n this.log('warn', `Skipped downloading post #${post.id}: not viewable by current user`);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.Inaccessible,\n skipMessage: 'Target is not viewable by current user'\n });\n skippedUnviewable++;\n continue;\n }\n }\n \n // -- 4.3.2: Config option 'include.postsWithMediaType'\n const postsWithMediaType = this.config.include.postsWithMediaType;\n if (postsWithMediaType !== 'any') {\n const hasAttachments = post.attachments.length > 0;\n const hasAudio = !!post.audio || !!post.audioPreview;\n const hasImages = post.images.length > 0;\n const hasVideo = !!post.video || !!post.videoPreview || !!(post.embed && post.embed.type === 'videoEmbed');\n \n let skip = false;\n if (postsWithMediaType === 'none') {\n skip = hasAttachments || hasAudio || hasImages || hasVideo;\n }\n else if (Array.isArray(postsWithMediaType)) {\n skip = !(\n (postsWithMediaType.includes('attachment') && hasAttachments) ||\n (postsWithMediaType.includes('audio') && hasAudio) ||\n (postsWithMediaType.includes('image') && hasImages) ||\n (postsWithMediaType.includes('video') && hasVideo));\n }\n \n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: unmet media type criteria`);\n this.log('debug', 'Match criteria failed:', `config.include.postsWithMediaType: ${JSON.stringify(postsWithMediaType)} <-> post #${post.id}:`, {\n hasAttachments,\n hasAudio,\n hasImages,\n hasVideo\n });\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.UnmetMediaTypeCriteria,\n skipMessage: 'Target does not meet media type criteria'\n });\n skippedUnmetMediaTypeCriteria++;\n continue;\n }\n }\n \n // -- 4.3.3: Config option 'include.postsInTier'\n const postsInTier = this.config.include.postsInTier;\n const isAnyTier = postsInTier === 'any' || postsInTier.includes('any');\n if (!isAnyTier) {\n const applicableTierIds = postsInTier.filter((id) => post.campaign?.rewards.find((r) => r.id === id));\n if (!post.campaign) {\n this.log('warn', 'config.include.postsInTier: ignored - post missing campaign info');\n }\n else {\n this.log('debug', 'config.include.postsInTier: applicable tier IDs:', applicableTierIds);\n }\n let skip = false;\n if (!post.campaign) {\n skip = false;\n }\n else if (applicableTierIds.length === 0) {\n skip = true;\n }\n else if (!post.tiers.find((tier) => tier.id === 'patrons')) {\n skip = applicableTierIds.every((id) => !post.tiers.find((tier) => tier.id === id));\n }\n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: not in tier`);\n this.log('debug', 'Match criteria failed:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.NotInTier,\n skipMessage: 'Target not in tier'\n });\n skippedNotInTier++;\n continue;\n }\n if (post.campaign) {\n this.log('debug', 'Match criteria OK:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);\n }\n }\n\n // -- 4.3.4: Config option 'include.postsPublished'\n const postsPublishedAfter = this.config.include.postsPublished.after;\n const postsPublishedBefore = this.config.include.postsPublished.before;\n if (postsPublishedAfter || postsPublishedBefore) {\n const targetPublishedAt = post.publishedAt;\n let parsedPublishedAt: Date | null = null;\n if (!targetPublishedAt) {\n this.log('warn', `config.include.postsPublished: ignored - post #${post.id} missing publish date`);\n }\n else {\n try {\n parsedPublishedAt = new Date(targetPublishedAt);\n }\n catch (error: any) {\n this.log('error', `Failed to parse publish date of post #${post.id} (\"${targetPublishedAt}\"): `, error);\n this.log('warn', `config.include.postsPublished: ignored - publish date of post #${post.id} could not be parsed`);\n }\n }\n let skip = false;\n if (parsedPublishedAt) {\n const isAfter = postsPublishedAfter ? parsedPublishedAt.getTime() >= postsPublishedAfter.valueOf().getTime() : true;\n const isBefore = postsPublishedBefore ? parsedPublishedAt.getTime() < postsPublishedBefore.valueOf().getTime() : true;\n skip = !isAfter || !isBefore;\n let eq: string | null = null;\n if (postsPublishedAfter && postsPublishedBefore) {\n eq = `${postsPublishedAfter.toString()} <= *${targetPublishedAt}* < ${postsPublishedBefore.toString()}`;\n }\n else if (postsPublishedAfter) {\n eq = `${postsPublishedAfter.toString()} <= *${targetPublishedAt}*`;\n }\n else if (postsPublishedBefore) {\n eq = `*${targetPublishedAt}* < ${postsPublishedBefore.toString()}`;\n }\n if (eq) {\n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: publish date out of range`);\n this.log('debug', `Publish date test failed for post #${post.id}: ${eq}`);\n }\n else {\n this.log('debug', `Publish date test OK for post #${post.id}: ${eq}`);\n }\n }\n if (skip) {\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.PublishDateOutOfRange,\n skipMessage: 'Publish date out of range'\n });\n skippedPublishDateOutOfRange++;\n continue;\n }\n }\n }\n\n \n // Step 4.4: Save post info\n if (this.config.include.contentInfo) {\n this.log('info', `Save post info #${post.id}`);\n this.emit('phaseBegin', { target: post, phase: 'saveInfo' });\n this.fsHelper.createDir(postDirs.info);\n // Post raw data might not be complete or consistent with other posts in the collection.\n // Fetch directly from API.\n // Strictly speaking, we should check for 'error' in results, but since it's not going to be fatal we'll just skip it.\n const { json: fetchedPostAPIData } = await this.commonFetchAPI(\n URLHelper.constructPostsAPIURL({\n postId: post.id,\n campaignId: post.campaign?.id\n }),\n signal\n );\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n // Save summary and raw json\n const summary = generatePostSummary(post);\n const summaryFile = path.resolve(postDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, post, 'post summary');\n \n const postRawFile = path.resolve(postDirs.info, 'post-api.json');\n const savePostRawResult = await this.fsHelper.writeTextFile(\n postRawFile, fetchedPostAPIData || post.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(savePostRawResult, post, 'post API data');\n this.emit('phaseEnd', { target: post, phase: 'saveInfo' });\n \n // (Downloading of info media items deferred to the next step)\n }\n \n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseBegin', { target: post, phase: 'saveMedia' });\n }\n \n // Step 4.5: save embed info\n if (post.embed && this.config.include.contentMedia) {\n this.log('info', `Save embed info of post #${post.id}`);\n this.fsHelper.createDir(postDirs.embed);\n const embedSummary = generatePostEmbedSummary(post.embed);\n let embedFilename;\n switch (post.embed.type) {\n case 'videoEmbed':\n embedFilename = 'embedded-video.txt';\n break;\n case 'linkEmbed':\n embedFilename = 'embedded-link.txt';\n break;\n default:\n embedFilename = 'embedded-unknown.txt';\n }\n const embedFile = path.resolve(postDirs.embed, embedFilename);\n const saveSummaryResult = await this.fsHelper.writeTextFile(embedFile, embedSummary, this.config.fileExistsAction.content);\n this.logWriteTextFileResult(saveSummaryResult, post, 'embed info');\n }\n \n // Step 4.6: create download tasks\n let createTaskErrorCount = 0;\n if (this.config.include.previewMedia ||\n this.config.include.contentMedia ||\n this.config.include.contentInfo) {\n \n const batchResult = await this.#createDownloadTaskBatchForPost(post, postDirs, signal);\n batch = batchResult.batch;\n createTaskErrorCount += batchResult.errorCount;\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n if (this.config.include.contentInfo) {\n const infoElements: Downloadable[] = [];\n if (post.coverImage) {\n infoElements.push(post.coverImage);\n }\n if (post.thumbnail) {\n infoElements.push(post.thumbnail);\n }\n if (infoElements.length > 0) {\n const { errorCount } = await this.addToDownloadTaskBatch(batch,\n signal,\n {\n target: infoElements,\n targetName: `post #${post.id} -> info elements`,\n destDir: postDirs.info,\n fileExistsAction: this.config.fileExistsAction.info\n }\n );\n createTaskErrorCount += errorCount;\n }\n }\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n batch.prestart();\n this.log('info', `Download batch created (#${batch.id}): ${batch.getTasks('pending').length} downloads pending`);\n this.emit('phaseBegin', { target: post, phase: 'batchDownload', batch });\n \n await batch.start();\n \n // Step 4.7: Update status cache\n statusCache.updateOnDownload(post, postDirs.root, batch.getTasks('error').length > 0 || createTaskErrorCount > 0, this.config);\n \n await batch.destroy();\n batch = null;\n this.emit('phaseEnd', { target: post, phase: 'batchDownload'});\n }\n \n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseEnd', { target: post, phase: 'saveMedia' });\n }\n \n downloaded++;\n this.emit('targetEnd', { target: post, isSkipped: false });\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n }\n }\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n // Done\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n if (postFetch.type === 'byUser') {\n this.log('info', `Done downloading posts by '${postFetch.vanity}'`);\n }\n else if (postFetch.type === 'byUserId') {\n this.log('info', `Done downloading posts by user #${postFetch.userId}`);\n }\n else if (postFetch.type === 'byCollection') {\n this.log('info', `Done downloading posts in collection #${postFetch.collectionId}`);\n }\n else {\n this.log('info', `Done downloading post #${postFetch.postId}`);\n }\n let endMessage = 'Done';\n if (this.#isFetchingMultiplePosts(postFetch)) {\n const skippedStrParts: string[] = [];\n if (skippedUnviewable) {\n skippedStrParts.push(`${skippedUnviewable} unviewable`);\n }\n if (skippedRedundant) {\n skippedStrParts.push(`${skippedRedundant} redundant`);\n }\n if (skippedUnmetMediaTypeCriteria) {\n skippedStrParts.push(`${skippedUnmetMediaTypeCriteria} with unmet media type criteria`);\n }\n if (skippedNotInTier) {\n skippedStrParts.push(`${skippedNotInTier} not in tier`);\n }\n if (skippedPublishDateOutOfRange) {\n skippedStrParts.push(`${skippedPublishDateOutOfRange} with publish date out of range`);\n }\n const skippedStr = skippedStrParts.length > 0 ? ` (skipped: ${skippedStrParts.join(', ')})` : '';\n endMessage = `Total ${downloaded} / ${postsFetcher.getTotal()} posts processed${skippedStr}`;\n this.log('info', endMessage);\n }\n this.emit('end', { aborted: false, message: endMessage });\n this.#startPromise = null;\n resolve();\n })();\n })\n .finally(() => {\n void (async () => {\n if (this.logger) {\n await this.logger.end();\n }\n this.#startPromise = null;\n })();\n });\n\n return this.#startPromise;\n }\n\n #isFetchingMultiplePosts(postFetch: DownloaderConfig<Post>['postFetch']): postFetch is DownloaderConfig<Post>['postFetch'] & { type: 'byUser' | 'byUserId' | 'byCollection' } {\n return postFetch.type === 'byUser' || postFetch.type === 'byUserId' || postFetch.type === 'byCollection';\n }\n\n async __getCampaign(signal?: AbortSignal) {\n let url: string | null;\n const postFetch = this.config.postFetch;\n switch (postFetch.type) {\n case 'byUser':\n url = URLHelper.constructCampaignPageURL({ vanity: postFetch.vanity });\n break;\n case 'byUserId':\n url = URLHelper.constructCampaignPageURL({ userId: postFetch.userId });\n break;\n default:\n url = null;\n }\n if (!url) {\n throw Error('Internal error: invalid config');\n }\n const postsFetcher = new PostsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n const { campaignId } = await postsFetcher.getInitialData(url);\n const postsParser = new PostParser(this.logger);\n const res = await this.fetchCampaign(campaignId);\n if (signal?.aborted) {\n throw new Error('Aborted');\n }\n if (res.error) {\n throw res.error;\n }\n return postsParser.parseCampaignAPIResponse(res.json);\n }\n\n #createDownloadTaskBatchForPost(post: Post, postDirs: ReturnType<typeof this.fsHelper['getPostDirs']>, signal?: AbortSignal) {\n\n const incPreview = this.config.include.previewMedia;\n const incContent = this.config.include.contentMedia;\n\n const __incPreview = (mediaType: 'audio' | 'video' | 'image') => {\n if (typeof incPreview === 'boolean') {\n return incPreview;\n }\n return incPreview.includes(mediaType);\n };\n\n const __incContent = (mediaType: 'audio' | 'video' | 'image' | 'attachment') => {\n if (typeof incContent === 'boolean') {\n return incContent;\n }\n return incContent.includes(mediaType);\n };\n\n const batchResult = this.createDownloadTaskBatch(\n `Post #${post.id} (${post.title})`,\n signal,\n\n __incPreview('audio') && post.audioPreview ? {\n target: [ post.audioPreview ],\n targetName: `post #${post.id} -> audio preview`,\n destDir: postDirs.audioPreview,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incPreview('video') && post.videoPreview ? {\n target: [ post.videoPreview ],\n targetName: `post #${post.id} -> video preview`,\n destDir: postDirs.videoPreview,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n /**\n * If post is not viewable by current user, its images will be\n * blurry and we should categorize them as image previews.\n */\n __incPreview('image') && post.images.length > 0 && !post.isViewable ? {\n target: post.images,\n targetName: `post #${post.id} -> image previews`,\n destDir: postDirs.imagePreviews,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('audio') && post.audio ? {\n target: [ post.audio ],\n targetName: `post #${post.id} -> audio`,\n destDir: postDirs.audio,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('video') && post.video ? {\n target: [ post.video ],\n targetName: `post #${post.id} -> video`,\n destDir: postDirs.video,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('image') && post.images.length > 0 && post.isViewable ? {\n target: post.images,\n targetName: `post #${post.id} -> images`,\n destDir: postDirs.images,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('attachment') && post.attachments.length > 0 ? {\n target: post.attachments,\n targetName: `post #${post.id} -> attachments`,\n destDir: postDirs.attachments,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('video') && post.embed &&\n (isYouTubeEmbed(post.embed) || DownloadTaskFactory.findEmbedDownloader(this.config.embedDownloaders, post.embed.provider)) ?\n {\n target: [ post.embed ],\n targetName: `post #${post.id} -> embedded ${post.embed.provider} video`,\n destDir: postDirs.embed,\n fileExistsAction: this.config.fileExistsAction.content\n } : null\n );\n\n return batchResult;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PostDownloader.js","sourceRoot":"","sources":["../../src/downloaders/PostDownloader.ts"],"names":[],"mappings":"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","sourcesContent":["import URLHelper from '../utils/URLHelper.js';\nimport Downloader, { type DownloaderConfig, type DownloaderStartParams } from './Downloader.js';\nimport type DownloadTaskBatch from './task/DownloadTaskBatch.js';\nimport PostParser from '../parsers/PostParser.js';\nimport { type Post } from '../entities/Post.js';\nimport { type Downloadable, isYouTubeEmbed } from '../entities/Downloadable.js';\nimport StatusCache from './cache/StatusCache.js';\nimport { generatePostEmbedSummary, generatePostSummary } from './templates/PostInfo.js';\nimport path from 'path';\nimport { TargetSkipReason } from './DownloaderEvent.js';\nimport DownloadTaskFactory from './task/DownloadTaskFactory.js';\nimport PostsFetcher from './PostsFetcher.js';\n\nexport default class PostDownloader extends Downloader<Post> {\n\n static version = '1.1.1';\n\n name = 'PostDownloader';\n\n #startPromise: Promise<void> | null = null;\n\n start(params?: DownloaderStartParams): Promise<void> {\n\n if (this.#startPromise) {\n throw Error('Downloader already running');\n }\n\n this.#startPromise = new Promise<void>((resolve) => {\n void (async () => {\n const { signal } = params || {};\n const postFetch = this.config.postFetch;\n let batch: DownloadTaskBatch | null = null;\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n const abortHandler = () => {\n void (async () => {\n this.log('info', 'Abort signal received');\n if (batch) {\n await batch.abort();\n }\n })();\n };\n if (signal) {\n signal.addEventListener('abort', abortHandler, { once: true });\n }\n \n if (postFetch.type === 'byUser') {\n this.log('info', `Targeting posts by '${postFetch.vanity}'`);\n }\n else if (postFetch.type === 'byUserId') {\n this.log('info', `Targeting posts by user #${postFetch.userId}`);\n }\n else if (postFetch.type === 'byCollection') {\n this.log('info', `Targeting posts in collection #${postFetch.collectionId}`);\n }\n else { // Single\n this.log('info', `Targeting post #${postFetch.postId}`);\n }\n if (this.#isFetchingMultiplePosts(postFetch) && postFetch.filters) {\n const filterStr = Object.entries(postFetch.filters).map(([ key, value ]) => `${key}=${value}`).join('; ');\n if (filterStr) {\n this.log('info', `Filters: ${filterStr}`);\n }\n }\n \n // Step 1: Get posts (if by user) or target post\n const postsFetcher = new PostsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n postsFetcher.on('statusChange', ({current}) => {\n if (current.status === 'running') {\n this.emit('fetchBegin', { targetType: postsFetcher.getTargetType() });\n }\n });\n postsFetcher.begin();\n \n // Step 2: download posts in each fetched collection\n let downloaded = 0;\n let skippedUnviewable = 0;\n let skippedRedundant = 0;\n let skippedUnmetMediaTypeCriteria = 0;\n let skippedNotInTier = 0;\n let skippedPublishDateOutOfRange = 0;\n let campaignSaved = false;\n const postsParser = new PostParser(this.logger);\n while (postsFetcher.hasNext()) {\n const { collection, aborted, error } = await postsFetcher.next();\n if (!collection || aborted) {\n break;\n }\n if (!collection && error) {\n this.emit('end', { aborted: false, error, message: 'PostsFetcher error' });\n resolve();\n return;\n }\n if (!campaignSaved && collection.posts[0]?.campaign) {\n await this.saveCampaignInfo(collection.posts[0].campaign, signal);\n campaignSaved = true;\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n }\n \n for (const _post of collection.posts) {\n \n let post = _post;\n \n if (this.#isFetchingMultiplePosts(postFetch)) {\n // Refresh to ensure media links have not expired\n this.log('debug', `Refresh post #${_post.id}`);\n const postURL = URLHelper.constructPostsAPIURL({ postId: _post.id });\n const { json } = await this.commonFetchAPI(postURL, signal);\n let refreshed: Post | null = null;\n if (json) {\n refreshed = postsParser.parsePostsAPIResponse(json, postURL).posts[0] || null;\n if (!refreshed) {\n this.log('warn', `Refreshed post #${_post.id} but got empty value - going to use existing data`);\n }\n else if (refreshed.id !== _post.id) {\n this.log('warn', `Refreshed post #${_post.id} but ID mismatch - going to use existing data`);\n refreshed = null;\n }\n }\n else if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n else {\n this.log('warn', `Failed to refresh post #${_post.id} - going to use existing data`);\n }\n if (refreshed) {\n this.log('debug', `Use refreshed post data #${refreshed.id}`);\n post = refreshed;\n }\n }\n \n this.emit('targetBegin', { target: post });\n \n // Step 4.1: post directories\n const postDirs = this.fsHelper.getPostDirs(post);\n this.log('debug', 'Post directories:', postDirs);\n \n // Step 4.2: Check with status cache\n const statusCache = StatusCache.getInstance(this.config, postDirs.statusCache, this.logger);\n if (statusCache.validate(post, postDirs.root, this.config)) {\n this.log('info', `Skipped downloading post #${post.id}: already downloaded and nothing has changed since last download`);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.AlreadyDownloaded,\n skipMessage: 'Target already downloaded and nothing has changed since last download'\n });\n skippedRedundant++;\n continue;\n }\n \n this.log('info', `Download post #${post.id} (${post.title})`);\n \n // Step 4.3: Check whether we should download post\n // -- 4.3.1: Viewability\n if (!post.isViewable) {\n if (this.config.include.lockedContent) {\n this.log('warn', `Post #${post.id} is not viewable by current user`);\n }\n else {\n this.log('warn', `Skipped downloading post #${post.id}: not viewable by current user`);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.Inaccessible,\n skipMessage: 'Target is not viewable by current user'\n });\n skippedUnviewable++;\n continue;\n }\n }\n \n // -- 4.3.2: Config option 'include.postsWithMediaType'\n const postsWithMediaType = this.config.include.postsWithMediaType;\n if (postsWithMediaType !== 'any') {\n const hasAttachments = post.attachments.length > 0;\n const hasAudio = !!post.audio || !!post.audioPreview;\n const hasImages = post.images.length > 0;\n const hasVideo = !!post.video || !!post.videoPreview || !!(post.embed && (post.embed.type === 'videoEmbed' || isYouTubeEmbed(post.embed)));\n \n let skip = false;\n if (postsWithMediaType === 'none') {\n skip = hasAttachments || hasAudio || hasImages || hasVideo;\n }\n else if (Array.isArray(postsWithMediaType)) {\n skip = !(\n (postsWithMediaType.includes('attachment') && hasAttachments) ||\n (postsWithMediaType.includes('audio') && hasAudio) ||\n (postsWithMediaType.includes('image') && hasImages) ||\n (postsWithMediaType.includes('video') && hasVideo));\n }\n \n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: unmet media type criteria`);\n this.log('debug', 'Match criteria failed:', `config.include.postsWithMediaType: ${JSON.stringify(postsWithMediaType)} <-> post #${post.id}:`, {\n hasAttachments,\n hasAudio,\n hasImages,\n hasVideo\n });\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.UnmetMediaTypeCriteria,\n skipMessage: 'Target does not meet media type criteria'\n });\n skippedUnmetMediaTypeCriteria++;\n continue;\n }\n }\n \n // -- 4.3.3: Config option 'include.postsInTier'\n const postsInTier = this.config.include.postsInTier;\n const isAnyTier = postsInTier === 'any' || postsInTier.includes('any');\n if (!isAnyTier) {\n const applicableTierIds = postsInTier.filter((id) => post.campaign?.rewards.find((r) => r.id === id));\n if (!post.campaign) {\n this.log('warn', 'config.include.postsInTier: ignored - post missing campaign info');\n }\n else {\n this.log('debug', 'config.include.postsInTier: applicable tier IDs:', applicableTierIds);\n }\n let skip = false;\n if (!post.campaign) {\n skip = false;\n }\n else if (applicableTierIds.length === 0) {\n skip = true;\n }\n else if (!post.tiers.find((tier) => tier.id === 'patrons')) {\n skip = applicableTierIds.every((id) => !post.tiers.find((tier) => tier.id === id));\n }\n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: not in tier`);\n this.log('debug', 'Match criteria failed:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.NotInTier,\n skipMessage: 'Target not in tier'\n });\n skippedNotInTier++;\n continue;\n }\n if (post.campaign) {\n this.log('debug', 'Match criteria OK:', `config.include.postsInTier: ${JSON.stringify(applicableTierIds)} <-> post #${post.id}:`, post.tiers);\n }\n }\n\n // -- 4.3.4: Config option 'include.postsPublished'\n const postsPublishedAfter = this.config.include.postsPublished.after;\n const postsPublishedBefore = this.config.include.postsPublished.before;\n if (postsPublishedAfter || postsPublishedBefore) {\n const targetPublishedAt = post.publishedAt;\n let parsedPublishedAt: Date | null = null;\n if (!targetPublishedAt) {\n this.log('warn', `config.include.postsPublished: ignored - post #${post.id} missing publish date`);\n }\n else {\n try {\n parsedPublishedAt = new Date(targetPublishedAt);\n }\n catch (error: any) {\n this.log('error', `Failed to parse publish date of post #${post.id} (\"${targetPublishedAt}\"): `, error);\n this.log('warn', `config.include.postsPublished: ignored - publish date of post #${post.id} could not be parsed`);\n }\n }\n let skip = false;\n if (parsedPublishedAt) {\n const isAfter = postsPublishedAfter ? parsedPublishedAt.getTime() >= postsPublishedAfter.valueOf().getTime() : true;\n const isBefore = postsPublishedBefore ? parsedPublishedAt.getTime() < postsPublishedBefore.valueOf().getTime() : true;\n skip = !isAfter || !isBefore;\n let eq: string | null = null;\n if (postsPublishedAfter && postsPublishedBefore) {\n eq = `${postsPublishedAfter.toString()} <= *${targetPublishedAt}* < ${postsPublishedBefore.toString()}`;\n }\n else if (postsPublishedAfter) {\n eq = `${postsPublishedAfter.toString()} <= *${targetPublishedAt}*`;\n }\n else if (postsPublishedBefore) {\n eq = `*${targetPublishedAt}* < ${postsPublishedBefore.toString()}`;\n }\n if (eq) {\n if (skip) {\n this.log('warn', `Skipped downloading post #${post.id}: publish date out of range`);\n this.log('debug', `Publish date test failed for post #${post.id}: ${eq}`);\n }\n else {\n this.log('debug', `Publish date test OK for post #${post.id}: ${eq}`);\n }\n }\n if (skip) {\n this.emit('targetEnd', {\n target: post,\n isSkipped: true,\n skipReason: TargetSkipReason.PublishDateOutOfRange,\n skipMessage: 'Publish date out of range'\n });\n skippedPublishDateOutOfRange++;\n continue;\n }\n }\n }\n\n \n // Step 4.4: Save post info\n if (this.config.include.contentInfo) {\n this.log('info', `Save post info #${post.id}`);\n this.emit('phaseBegin', { target: post, phase: 'saveInfo' });\n this.fsHelper.createDir(postDirs.info);\n // Post raw data might not be complete or consistent with other posts in the collection.\n // Fetch directly from API.\n // Strictly speaking, we should check for 'error' in results, but since it's not going to be fatal we'll just skip it.\n const { json: fetchedPostAPIData } = await this.commonFetchAPI(\n URLHelper.constructPostsAPIURL({\n postId: post.id,\n campaignId: post.campaign?.id\n }),\n signal\n );\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n // Save summary and raw json\n const summary = generatePostSummary(post);\n const summaryFile = path.resolve(postDirs.info, 'info.txt');\n const saveSummaryResult = await this.fsHelper.writeTextFile(summaryFile, summary, this.config.fileExistsAction.info);\n this.logWriteTextFileResult(saveSummaryResult, post, 'post summary');\n \n const postRawFile = path.resolve(postDirs.info, 'post-api.json');\n const savePostRawResult = await this.fsHelper.writeTextFile(\n postRawFile, fetchedPostAPIData || post.raw, this.config.fileExistsAction.infoAPI);\n this.logWriteTextFileResult(savePostRawResult, post, 'post API data');\n this.emit('phaseEnd', { target: post, phase: 'saveInfo' });\n \n // (Downloading of info media items deferred to the next step)\n }\n \n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseBegin', { target: post, phase: 'saveMedia' });\n }\n \n // Step 4.5: save embed info\n if (post.embed && this.config.include.contentMedia) {\n this.log('info', `Save embed info of post #${post.id}`);\n this.fsHelper.createDir(postDirs.embed);\n const embedSummary = generatePostEmbedSummary(post.embed);\n let embedFilename;\n switch (post.embed.type) {\n case 'videoEmbed':\n embedFilename = 'embedded-video.txt';\n break;\n case 'linkEmbed':\n embedFilename = 'embedded-link.txt';\n break;\n default:\n embedFilename = 'embedded-unknown.txt';\n }\n const embedFile = path.resolve(postDirs.embed, embedFilename);\n const saveSummaryResult = await this.fsHelper.writeTextFile(embedFile, embedSummary, this.config.fileExistsAction.content);\n this.logWriteTextFileResult(saveSummaryResult, post, 'embed info');\n }\n \n // Step 4.6: create download tasks\n let createTaskErrorCount = 0;\n if (this.config.include.previewMedia ||\n this.config.include.contentMedia ||\n this.config.include.contentInfo) {\n \n const batchResult = await this.#createDownloadTaskBatchForPost(post, postDirs, signal);\n batch = batchResult.batch;\n createTaskErrorCount += batchResult.errorCount;\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n if (this.config.include.contentInfo) {\n const infoElements: Downloadable[] = [];\n if (post.coverImage) {\n infoElements.push(post.coverImage);\n }\n if (post.thumbnail) {\n infoElements.push(post.thumbnail);\n }\n if (infoElements.length > 0) {\n const { errorCount } = await this.addToDownloadTaskBatch(batch,\n signal,\n {\n target: infoElements,\n targetName: `post #${post.id} -> info elements`,\n destDir: postDirs.info,\n fileExistsAction: this.config.fileExistsAction.info\n }\n );\n createTaskErrorCount += errorCount;\n }\n }\n\n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n batch.prestart();\n this.log('info', `Download batch created (#${batch.id}): ${batch.getTasks('pending').length} downloads pending`);\n this.emit('phaseBegin', { target: post, phase: 'batchDownload', batch });\n \n await batch.start();\n \n // Step 4.7: Update status cache\n statusCache.updateOnDownload(post, postDirs.root, batch.getTasks('error').length > 0 || createTaskErrorCount > 0, this.config);\n \n await batch.destroy();\n batch = null;\n this.emit('phaseEnd', { target: post, phase: 'batchDownload'});\n }\n \n if (this.config.include.previewMedia || this.config.include.contentMedia) {\n this.emit('phaseEnd', { target: post, phase: 'saveMedia' });\n }\n \n downloaded++;\n this.emit('targetEnd', { target: post, isSkipped: false });\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n }\n }\n \n if (this.checkAbortSignal(signal, resolve)) {\n return;\n }\n \n // Done\n if (signal) {\n signal.removeEventListener('abort', abortHandler);\n }\n if (postFetch.type === 'byUser') {\n this.log('info', `Done downloading posts by '${postFetch.vanity}'`);\n }\n else if (postFetch.type === 'byUserId') {\n this.log('info', `Done downloading posts by user #${postFetch.userId}`);\n }\n else if (postFetch.type === 'byCollection') {\n this.log('info', `Done downloading posts in collection #${postFetch.collectionId}`);\n }\n else {\n this.log('info', `Done downloading post #${postFetch.postId}`);\n }\n let endMessage = 'Done';\n if (this.#isFetchingMultiplePosts(postFetch)) {\n const skippedStrParts: string[] = [];\n if (skippedUnviewable) {\n skippedStrParts.push(`${skippedUnviewable} unviewable`);\n }\n if (skippedRedundant) {\n skippedStrParts.push(`${skippedRedundant} redundant`);\n }\n if (skippedUnmetMediaTypeCriteria) {\n skippedStrParts.push(`${skippedUnmetMediaTypeCriteria} with unmet media type criteria`);\n }\n if (skippedNotInTier) {\n skippedStrParts.push(`${skippedNotInTier} not in tier`);\n }\n if (skippedPublishDateOutOfRange) {\n skippedStrParts.push(`${skippedPublishDateOutOfRange} with publish date out of range`);\n }\n const skippedStr = skippedStrParts.length > 0 ? ` (skipped: ${skippedStrParts.join(', ')})` : '';\n endMessage = `Total ${downloaded} / ${postsFetcher.getTotal()} posts processed${skippedStr}`;\n this.log('info', endMessage);\n }\n this.emit('end', { aborted: false, message: endMessage });\n this.#startPromise = null;\n resolve();\n })();\n })\n .finally(() => {\n void (async () => {\n if (this.logger) {\n await this.logger.end();\n }\n this.#startPromise = null;\n })();\n });\n\n return this.#startPromise;\n }\n\n #isFetchingMultiplePosts(postFetch: DownloaderConfig<Post>['postFetch']): postFetch is DownloaderConfig<Post>['postFetch'] & { type: 'byUser' | 'byUserId' | 'byCollection' } {\n return postFetch.type === 'byUser' || postFetch.type === 'byUserId' || postFetch.type === 'byCollection';\n }\n\n async __getCampaign(signal?: AbortSignal) {\n let url: string | null;\n const postFetch = this.config.postFetch;\n switch (postFetch.type) {\n case 'byUser':\n url = URLHelper.constructCampaignPageURL({ vanity: postFetch.vanity });\n break;\n case 'byUserId':\n url = URLHelper.constructCampaignPageURL({ userId: postFetch.userId });\n break;\n default:\n url = null;\n }\n if (!url) {\n throw Error('Internal error: invalid config');\n }\n const postsFetcher = new PostsFetcher({\n config: this.config,\n fetcher: this.fetcher,\n logger: this.logger,\n signal\n });\n const { campaignId } = await postsFetcher.getInitialData(url);\n const postsParser = new PostParser(this.logger);\n const res = await this.fetchCampaign(campaignId);\n if (signal?.aborted) {\n throw new Error('Aborted');\n }\n if (res.error) {\n throw res.error;\n }\n return postsParser.parseCampaignAPIResponse(res.json);\n }\n\n #createDownloadTaskBatchForPost(post: Post, postDirs: ReturnType<typeof this.fsHelper['getPostDirs']>, signal?: AbortSignal) {\n\n const incPreview = this.config.include.previewMedia;\n const incContent = this.config.include.contentMedia;\n\n const __incPreview = (mediaType: 'audio' | 'video' | 'image') => {\n if (typeof incPreview === 'boolean') {\n return incPreview;\n }\n return incPreview.includes(mediaType);\n };\n\n const __incContent = (mediaType: 'audio' | 'video' | 'image' | 'attachment') => {\n if (typeof incContent === 'boolean') {\n return incContent;\n }\n return incContent.includes(mediaType);\n };\n\n const __getEmbedTask = () => {\n if (!post.embed) {\n return null;\n }\n\n const hasEmbedDownloader = DownloadTaskFactory.findEmbedDownloader(this.config.embedDownloaders, post.embed.provider);\n const isDownloadableVideo = isYouTubeEmbed(post.embed) || (post.embed.type === 'videoEmbed' && hasEmbedDownloader);\n const isDownloadableOther = !isYouTubeEmbed(post.embed) && post.embed.type !== 'videoEmbed' && hasEmbedDownloader;\n \n if ((isDownloadableVideo && __incContent('video')) || isDownloadableOther) {\n const embedType = post.embed.type === 'videoEmbed' ? ' video' : post.embed.type === 'linkEmbed' ? ' link' : '';\n return {\n target: [ post.embed ],\n targetName: `post #${post.id} -> embedded ${post.embed.provider}${embedType}`,\n destDir: postDirs.embed,\n fileExistsAction: this.config.fileExistsAction.content\n };\n }\n \n return null;\n }\n\n const batchResult = this.createDownloadTaskBatch(\n `Post #${post.id} (${post.title})`,\n signal,\n\n __incPreview('audio') && post.audioPreview ? {\n target: [ post.audioPreview ],\n targetName: `post #${post.id} -> audio preview`,\n destDir: postDirs.audioPreview,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incPreview('video') && post.videoPreview ? {\n target: [ post.videoPreview ],\n targetName: `post #${post.id} -> video preview`,\n destDir: postDirs.videoPreview,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n /**\n * If post is not viewable by current user, its images will be\n * blurry and we should categorize them as image previews.\n */\n __incPreview('image') && post.images.length > 0 && !post.isViewable ? {\n target: post.images,\n targetName: `post #${post.id} -> image previews`,\n destDir: postDirs.imagePreviews,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('audio') && post.audio ? {\n target: [ post.audio ],\n targetName: `post #${post.id} -> audio`,\n destDir: postDirs.audio,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('video') && post.video ? {\n target: [ post.video ],\n targetName: `post #${post.id} -> video`,\n destDir: postDirs.video,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('image') && post.images.length > 0 && post.isViewable ? {\n target: post.images,\n targetName: `post #${post.id} -> images`,\n destDir: postDirs.images,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __incContent('attachment') && post.attachments.length > 0 ? {\n target: post.attachments,\n targetName: `post #${post.id} -> attachments`,\n destDir: postDirs.attachments,\n fileExistsAction: this.config.fileExistsAction.content\n } : null,\n\n __getEmbedTask()\n );\n\n return batchResult;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadTaskFactory.d.ts","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAC,KAAK,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAC7D,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,KAAK,YAAY,EAA2B,MAAM,gCAAgC,CAAC;AAC5F,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACtF,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AAGxD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAqCzC,MAAM,CAAC,OAAO,OAAO,mBAAmB;;
|
|
1
|
+
{"version":3,"file":"DownloadTaskFactory.d.ts","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAC,KAAK,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAC7D,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,KAAK,YAAY,EAA2B,MAAM,gCAAgC,CAAC;AAC5F,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACtF,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AAGxD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC;AAqCzC,MAAM,CAAC,OAAO,OAAO,mBAAmB;;WAyEzB,sBAAsB,CAAC,MAAM,EAAE;QAC1C,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,EAAE,YAAY,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,SAAS,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;QACzC,OAAO,EAAE,UAAU,CAAC;QACpB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB;IA4HD,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,eAAe,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CAG5E"}
|
|
@@ -3,7 +3,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
3
3
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
|
-
var _a, _DownloadTaskFactory_pickVariant;
|
|
6
|
+
var _a, _DownloadTaskFactory_getSrcURLs, _DownloadTaskFactory_pickVariant;
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import MediaFilenameResolver from '../../utils/MediaFilenameResolver.js';
|
|
9
9
|
import DownloadTask from './DownloadTask.js';
|
|
@@ -47,106 +47,32 @@ class DownloadTaskFactory {
|
|
|
47
47
|
const embedDownloaders = config.embedDownloaders;
|
|
48
48
|
const destFilenameFormat = config.filenameFormat.media;
|
|
49
49
|
const downloadAllVariants = config.include.allMediaVariants;
|
|
50
|
-
const __getSrcURLs = () => {
|
|
51
|
-
if (item.type === 'image') {
|
|
52
|
-
let urls = {};
|
|
53
|
-
let priority = [];
|
|
54
|
-
switch (item.imageType) {
|
|
55
|
-
case 'single':
|
|
56
|
-
return {
|
|
57
|
-
[NULL_VARIANT]: item.imageURL
|
|
58
|
-
};
|
|
59
|
-
case 'default':
|
|
60
|
-
urls = {
|
|
61
|
-
...item.imageURLs,
|
|
62
|
-
download: item.downloadURL
|
|
63
|
-
};
|
|
64
|
-
priority = DEFAULT_IMAGE_URL_PRIORITY;
|
|
65
|
-
break;
|
|
66
|
-
case 'campaignCoverPhoto':
|
|
67
|
-
urls = item.imageURLs;
|
|
68
|
-
priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;
|
|
69
|
-
break;
|
|
70
|
-
case 'postCoverImage':
|
|
71
|
-
urls = item.imageURLs;
|
|
72
|
-
priority = POST_COVER_IMAGE_URL_PRIORITY;
|
|
73
|
-
break;
|
|
74
|
-
case 'postThumbnail':
|
|
75
|
-
urls = item.imageURLs;
|
|
76
|
-
priority = POST_THUMBNAIL_URL_PRIORITY;
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
if (downloadAllVariants) {
|
|
80
|
-
return urls;
|
|
81
|
-
}
|
|
82
|
-
return __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_pickVariant).call(this, urls, priority);
|
|
83
|
-
}
|
|
84
|
-
else if (item.type === 'video') {
|
|
85
|
-
let videoVariantName = 'display';
|
|
86
|
-
if (item.size.width && item.size.height) {
|
|
87
|
-
videoVariantName = `${item.size.width}x${item.size.height}`;
|
|
88
|
-
}
|
|
89
|
-
const urls = {
|
|
90
|
-
download: item.downloadURL,
|
|
91
|
-
[videoVariantName]: item.displayURLs.video
|
|
92
|
-
};
|
|
93
|
-
if (downloadAllVariants) {
|
|
94
|
-
return urls;
|
|
95
|
-
}
|
|
96
|
-
const priority = ['download', videoVariantName];
|
|
97
|
-
return __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_pickVariant).call(this, urls, priority);
|
|
98
|
-
}
|
|
99
|
-
else if (item.type === 'audio') {
|
|
100
|
-
return {
|
|
101
|
-
[NULL_VARIANT]: item.url
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
else if (item.type === 'file') {
|
|
105
|
-
return {
|
|
106
|
-
[NULL_VARIANT]: item.downloadURL
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
else if (item.type === 'dummy') {
|
|
110
|
-
return item.srcURLs;
|
|
111
|
-
}
|
|
112
|
-
else if (item.type === 'attachment') {
|
|
113
|
-
return {
|
|
114
|
-
[NULL_VARIANT]: item.downloadURL
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
else if (item.type === 'videoEmbed') {
|
|
118
|
-
return {
|
|
119
|
-
[NULL_VARIANT]: item.url
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
return {};
|
|
123
|
-
};
|
|
124
|
-
const srcURLs = __getSrcURLs();
|
|
125
50
|
const tasks = [];
|
|
126
|
-
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
tasks.push(task);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Use our own implementation if no external downloader configured for YT embeds
|
|
137
|
-
else if (item.type === 'videoEmbed' && isYouTubeEmbed(item) && url) {
|
|
138
|
-
tasks.push(await DownloadTask.create(YouTubeDownloadTask, {
|
|
139
|
-
config,
|
|
140
|
-
src: url,
|
|
141
|
-
destDir,
|
|
142
|
-
fileExistsAction,
|
|
143
|
-
srcEntity: item,
|
|
144
|
-
callbacks: callbacks || null,
|
|
145
|
-
logger
|
|
146
|
-
}, limiter, signal));
|
|
51
|
+
if (isEmbed(item)) {
|
|
52
|
+
// Check if external downloader configured for embed item
|
|
53
|
+
const embedDownloader = this.findEmbedDownloader(embedDownloaders, item.provider);
|
|
54
|
+
if (embedDownloader) {
|
|
55
|
+
const task = ExternalDownloaderTask.fromEmbedDownloader(config, embedDownloader, item, destDir, callbacks || null, logger);
|
|
56
|
+
if (task) {
|
|
57
|
+
tasks.push(task);
|
|
147
58
|
}
|
|
148
59
|
}
|
|
149
|
-
|
|
60
|
+
// Use our own implementation if no external downloader configured for YT embeds
|
|
61
|
+
else if (isYouTubeEmbed(item) && item.url) {
|
|
62
|
+
tasks.push(await DownloadTask.create(YouTubeDownloadTask, {
|
|
63
|
+
config,
|
|
64
|
+
src: item.url,
|
|
65
|
+
destDir,
|
|
66
|
+
fileExistsAction,
|
|
67
|
+
srcEntity: item,
|
|
68
|
+
callbacks: callbacks || null,
|
|
69
|
+
logger
|
|
70
|
+
}, limiter, signal));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const srcURLs = __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_getSrcURLs).call(this, item, downloadAllVariants);
|
|
75
|
+
for (const [variant, url] of Object.entries(srcURLs)) {
|
|
150
76
|
const destFilenameResolver = new MediaFilenameResolver(item, url, destFilenameFormat, variant !== NULL_VARIANT ? variant : null, downloadAllVariants);
|
|
151
77
|
if (url) {
|
|
152
78
|
tasks.push(await DownloadTask.create(FetcherDownloadTask, {
|
|
@@ -207,7 +133,75 @@ class DownloadTaskFactory {
|
|
|
207
133
|
return edl.find((dl) => dl.provider.toLowerCase() === provider?.trim().toLowerCase());
|
|
208
134
|
}
|
|
209
135
|
}
|
|
210
|
-
_a = DownloadTaskFactory,
|
|
136
|
+
_a = DownloadTaskFactory, _DownloadTaskFactory_getSrcURLs = function _DownloadTaskFactory_getSrcURLs(item, allVariants) {
|
|
137
|
+
if (item.type === 'image') {
|
|
138
|
+
let urls = {};
|
|
139
|
+
let priority = [];
|
|
140
|
+
switch (item.imageType) {
|
|
141
|
+
case 'single':
|
|
142
|
+
return {
|
|
143
|
+
[NULL_VARIANT]: item.imageURL
|
|
144
|
+
};
|
|
145
|
+
case 'default':
|
|
146
|
+
urls = {
|
|
147
|
+
...item.imageURLs,
|
|
148
|
+
download: item.downloadURL
|
|
149
|
+
};
|
|
150
|
+
priority = DEFAULT_IMAGE_URL_PRIORITY;
|
|
151
|
+
break;
|
|
152
|
+
case 'campaignCoverPhoto':
|
|
153
|
+
urls = item.imageURLs;
|
|
154
|
+
priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;
|
|
155
|
+
break;
|
|
156
|
+
case 'postCoverImage':
|
|
157
|
+
urls = item.imageURLs;
|
|
158
|
+
priority = POST_COVER_IMAGE_URL_PRIORITY;
|
|
159
|
+
break;
|
|
160
|
+
case 'postThumbnail':
|
|
161
|
+
urls = item.imageURLs;
|
|
162
|
+
priority = POST_THUMBNAIL_URL_PRIORITY;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
if (allVariants) {
|
|
166
|
+
return urls;
|
|
167
|
+
}
|
|
168
|
+
return __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_pickVariant).call(this, urls, priority);
|
|
169
|
+
}
|
|
170
|
+
else if (item.type === 'video') {
|
|
171
|
+
let videoVariantName = 'display';
|
|
172
|
+
if (item.size.width && item.size.height) {
|
|
173
|
+
videoVariantName = `${item.size.width}x${item.size.height}`;
|
|
174
|
+
}
|
|
175
|
+
const urls = {
|
|
176
|
+
download: item.downloadURL,
|
|
177
|
+
[videoVariantName]: item.displayURLs.video
|
|
178
|
+
};
|
|
179
|
+
if (allVariants) {
|
|
180
|
+
return urls;
|
|
181
|
+
}
|
|
182
|
+
const priority = ['download', videoVariantName];
|
|
183
|
+
return __classPrivateFieldGet(this, _a, "m", _DownloadTaskFactory_pickVariant).call(this, urls, priority);
|
|
184
|
+
}
|
|
185
|
+
else if (item.type === 'audio') {
|
|
186
|
+
return {
|
|
187
|
+
[NULL_VARIANT]: item.url
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
else if (item.type === 'file') {
|
|
191
|
+
return {
|
|
192
|
+
[NULL_VARIANT]: item.downloadURL
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
else if (item.type === 'dummy') {
|
|
196
|
+
return item.srcURLs;
|
|
197
|
+
}
|
|
198
|
+
else if (item.type === 'attachment') {
|
|
199
|
+
return {
|
|
200
|
+
[NULL_VARIANT]: item.downloadURL
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {};
|
|
204
|
+
}, _DownloadTaskFactory_pickVariant = function _DownloadTaskFactory_pickVariant(urls, priority) {
|
|
211
205
|
for (const variant of priority) {
|
|
212
206
|
if (urls[variant]) {
|
|
213
207
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DownloadTaskFactory.js","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { type DummyMediaItem } from '../../entities/MediaItem.js';\nimport type Fetcher from '../../utils/Fetcher.js';\nimport MediaFilenameResolver from '../../utils/MediaFilenameResolver.js';\nimport {type DownloadTaskCallbacks} from './DownloadTask.js';\nimport DownloadTask from './DownloadTask.js';\nimport FetcherDownloadTask from './FetcherDownloadTask.js';\nimport { type Downloadable, isEmbed, isYouTubeEmbed } from '../../entities/Downloadable.js';\nimport { type EmbedDownloader, type FileExistsAction } from '../DownloaderOptions.js';\nimport type Logger from '../../utils/logging/Logger.js';\nimport YouTubeDownloadTask from './YouTubeDownloadTask.js';\nimport ExternalDownloaderTask from './ExternalDownloaderTask.js';\nimport { type DownloaderConfig } from '../Downloader.js';\nimport type Bottleneck from 'bottleneck';\n\nconst DEFAULT_IMAGE_URL_PRIORITY = [\n 'original',\n 'default',\n 'download',\n 'defaultSmall',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst CAMPAIGN_COVER_PHOTO_URL_PRIORITY = [\n 'xlarge',\n 'large',\n 'medium',\n 'small',\n 'xsmall'\n];\n\nconst POST_COVER_IMAGE_URL_PRIORITY = [\n 'large',\n 'default',\n 'thumb',\n 'thumbSquareLarge',\n 'thumbSquare'\n];\n\nconst POST_THUMBNAIL_URL_PRIORITY = [\n 'large2',\n 'default',\n 'large',\n 'square'\n];\n\nconst NULL_VARIANT = '/*NULL*/';\n\nexport default class DownloadTaskFactory {\n\n static async createFromDownloadable(params: {\n config: DownloaderConfig<any>,\n item: Downloadable,\n destDir: string,\n fetcher: Fetcher,\n fileExistsAction: FileExistsAction,\n callbacks?: DownloadTaskCallbacks | null,\n limiter: Bottleneck,\n signal?: AbortSignal,\n logger?: Logger | null;\n }) {\n\n const {\n config,\n item,\n destDir,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n } = params;\n\n const embedDownloaders = config.embedDownloaders;\n const destFilenameFormat = config.filenameFormat.media;\n const downloadAllVariants = config.include.allMediaVariants;\n\n const __getSrcURLs = () => {\n if (item.type === 'image') {\n let urls: Record<string, string | null> = {};\n let priority: string[] = [];\n switch (item.imageType) {\n case 'single':\n return {\n [NULL_VARIANT]: item.imageURL\n };\n case 'default':\n urls = {\n ...item.imageURLs,\n download: item.downloadURL\n };\n priority = DEFAULT_IMAGE_URL_PRIORITY;\n break;\n case 'campaignCoverPhoto':\n urls = item.imageURLs;\n priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;\n break;\n case 'postCoverImage':\n urls = item.imageURLs;\n priority = POST_COVER_IMAGE_URL_PRIORITY;\n break;\n case 'postThumbnail':\n urls = item.imageURLs;\n priority = POST_THUMBNAIL_URL_PRIORITY;\n break;\n }\n if (downloadAllVariants) {\n return urls;\n }\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'video') {\n let videoVariantName = 'display';\n if (item.size.width && item.size.height) {\n videoVariantName = `${item.size.width}x${item.size.height}`;\n }\n const urls = {\n download: item.downloadURL,\n [videoVariantName]: item.displayURLs.video\n };\n if (downloadAllVariants) {\n return urls;\n }\n const priority = [ 'download', videoVariantName ];\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'audio') {\n return {\n [NULL_VARIANT]: item.url\n };\n }\n else if (item.type === 'file') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n else if (item.type === 'dummy') {\n return item.srcURLs;\n }\n else if (item.type === 'attachment') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n else if (item.type === 'videoEmbed') {\n return {\n [NULL_VARIANT]: item.url\n };\n }\n return {};\n };\n\n\n const srcURLs = __getSrcURLs();\n\n const tasks: DownloadTask[] = [];\n for (const [ variant, url ] of Object.entries(srcURLs)) {\n if (isEmbed(item)) {\n // Check if external downloader configured for embed item\n const embedDownloader = this.findEmbedDownloader(embedDownloaders, item.provider);\n if (embedDownloader) {\n const task = ExternalDownloaderTask.fromEmbedDownloader(config, embedDownloader, item, destDir, callbacks || null, logger);\n if (task) {\n tasks.push(task);\n }\n }\n // Use our own implementation if no external downloader configured for YT embeds\n else if (item.type === 'videoEmbed' && isYouTubeEmbed(item) && url) {\n tasks.push(await DownloadTask.create(YouTubeDownloadTask, {\n config,\n src: url,\n destDir,\n fileExistsAction,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n else {\n const destFilenameResolver = \n new MediaFilenameResolver(item, url, destFilenameFormat,\n variant !== NULL_VARIANT ? variant : null, downloadAllVariants);\n\n if (url) {\n tasks.push(await DownloadTask.create(FetcherDownloadTask, {\n config,\n fetcher,\n src: url,\n destDir,\n destFilenameResolver,\n fileExistsAction,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n }\n\n // Create a DownloadTask backed by a DummyMediaItem for video thumbnail\n if (item.type === 'video' && item.displayURLs.thumbnail) {\n let filename: string | null = null;\n if (item.filename) {\n // Video file extension not applicable to thumbnail, so strip it.\n filename = path.parse(item.filename).name;\n }\n const videoThumbnailMediaItem: DummyMediaItem = {\n type: 'dummy',\n id: item.id,\n filename,\n mimeType: null,\n srcURLs: {\n thumbnail: item.displayURLs.thumbnail\n }\n };\n const __config = {\n ...config,\n include: {\n ...config.include,\n allMediaVariants: true // Ensure variant name ('thumbnail') appears in dest filename\n }\n };\n tasks.push(\n ...await this.createFromDownloadable({\n config: __config,\n item: videoThumbnailMediaItem,\n destDir,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n })\n );\n }\n\n if (tasks.length === 0) {\n throw Error('No src URL found');\n }\n\n return tasks;\n }\n\n static #pickVariant(urls: Record<string, any>, priority: string[]) {\n for (const variant of priority) {\n if (urls[variant]) {\n return {\n [variant]: urls[variant]\n };\n }\n }\n return {};\n }\n\n static findEmbedDownloader(edl: EmbedDownloader[], provider?: string | null) {\n return edl.find((dl) => dl.provider.toLowerCase() === provider?.trim().toLowerCase());\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DownloadTaskFactory.js","sourceRoot":"","sources":["../../../src/downloaders/task/DownloadTaskFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { type DummyMediaItem } from '../../entities/MediaItem.js';\nimport type Fetcher from '../../utils/Fetcher.js';\nimport MediaFilenameResolver from '../../utils/MediaFilenameResolver.js';\nimport {type DownloadTaskCallbacks} from './DownloadTask.js';\nimport DownloadTask from './DownloadTask.js';\nimport FetcherDownloadTask from './FetcherDownloadTask.js';\nimport { type Downloadable, isEmbed, isYouTubeEmbed } from '../../entities/Downloadable.js';\nimport { type EmbedDownloader, type FileExistsAction } from '../DownloaderOptions.js';\nimport type Logger from '../../utils/logging/Logger.js';\nimport YouTubeDownloadTask from './YouTubeDownloadTask.js';\nimport ExternalDownloaderTask from './ExternalDownloaderTask.js';\nimport { type DownloaderConfig } from '../Downloader.js';\nimport type Bottleneck from 'bottleneck';\n\nconst DEFAULT_IMAGE_URL_PRIORITY = [\n 'original',\n 'default',\n 'download',\n 'defaultSmall',\n 'thumbnailLarge',\n 'thumbnail',\n 'thumbnailSmall'\n];\n\nconst CAMPAIGN_COVER_PHOTO_URL_PRIORITY = [\n 'xlarge',\n 'large',\n 'medium',\n 'small',\n 'xsmall'\n];\n\nconst POST_COVER_IMAGE_URL_PRIORITY = [\n 'large',\n 'default',\n 'thumb',\n 'thumbSquareLarge',\n 'thumbSquare'\n];\n\nconst POST_THUMBNAIL_URL_PRIORITY = [\n 'large2',\n 'default',\n 'large',\n 'square'\n];\n\nconst NULL_VARIANT = '/*NULL*/';\n\nexport default class DownloadTaskFactory {\n\n static #getSrcURLs(item: Downloadable, allVariants: boolean) {\n if (item.type === 'image') {\n let urls: Record<string, string | null> = {};\n let priority: string[] = [];\n switch (item.imageType) {\n case 'single':\n return {\n [NULL_VARIANT]: item.imageURL\n };\n case 'default':\n urls = {\n ...item.imageURLs,\n download: item.downloadURL\n };\n priority = DEFAULT_IMAGE_URL_PRIORITY;\n break;\n case 'campaignCoverPhoto':\n urls = item.imageURLs;\n priority = CAMPAIGN_COVER_PHOTO_URL_PRIORITY;\n break;\n case 'postCoverImage':\n urls = item.imageURLs;\n priority = POST_COVER_IMAGE_URL_PRIORITY;\n break;\n case 'postThumbnail':\n urls = item.imageURLs;\n priority = POST_THUMBNAIL_URL_PRIORITY;\n break;\n }\n if (allVariants) {\n return urls;\n }\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'video') {\n let videoVariantName = 'display';\n if (item.size.width && item.size.height) {\n videoVariantName = `${item.size.width}x${item.size.height}`;\n }\n const urls = {\n download: item.downloadURL,\n [videoVariantName]: item.displayURLs.video\n };\n if (allVariants) {\n return urls;\n }\n const priority = [ 'download', videoVariantName ];\n return this.#pickVariant(urls, priority);\n }\n else if (item.type === 'audio') {\n return {\n [NULL_VARIANT]: item.url\n };\n }\n else if (item.type === 'file') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n else if (item.type === 'dummy') {\n return item.srcURLs;\n }\n else if (item.type === 'attachment') {\n return {\n [NULL_VARIANT]: item.downloadURL\n };\n }\n\n return {};\n }\n\n static async createFromDownloadable(params: {\n config: DownloaderConfig<any>,\n item: Downloadable,\n destDir: string,\n fetcher: Fetcher,\n fileExistsAction: FileExistsAction,\n callbacks?: DownloadTaskCallbacks | null,\n limiter: Bottleneck,\n signal?: AbortSignal,\n logger?: Logger | null;\n }) {\n\n const {\n config,\n item,\n destDir,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n } = params;\n\n const embedDownloaders = config.embedDownloaders;\n const destFilenameFormat = config.filenameFormat.media;\n const downloadAllVariants = config.include.allMediaVariants;\n const tasks: DownloadTask[] = [];\n\n if (isEmbed(item)) {\n // Check if external downloader configured for embed item\n const embedDownloader = this.findEmbedDownloader(embedDownloaders, item.provider);\n if (embedDownloader) {\n const task = ExternalDownloaderTask.fromEmbedDownloader(config, embedDownloader, item, destDir, callbacks || null, logger);\n if (task) {\n tasks.push(task);\n }\n }\n // Use our own implementation if no external downloader configured for YT embeds\n else if (isYouTubeEmbed(item) && item.url) {\n tasks.push(await DownloadTask.create(YouTubeDownloadTask, {\n config,\n src: item.url,\n destDir,\n fileExistsAction,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n else {\n const srcURLs = this.#getSrcURLs(item, downloadAllVariants);\n for (const [ variant, url ] of Object.entries(srcURLs)) {\n const destFilenameResolver = \n new MediaFilenameResolver(item, url, destFilenameFormat,\n variant !== NULL_VARIANT ? variant : null, downloadAllVariants);\n\n if (url) {\n tasks.push(await DownloadTask.create(FetcherDownloadTask, {\n config,\n fetcher,\n src: url,\n destDir,\n destFilenameResolver,\n fileExistsAction,\n srcEntity: item,\n callbacks: callbacks || null,\n logger\n },\n limiter,\n signal));\n }\n }\n } \n \n // Create a DownloadTask backed by a DummyMediaItem for video thumbnail\n if (item.type === 'video' && item.displayURLs.thumbnail) {\n let filename: string | null = null;\n if (item.filename) {\n // Video file extension not applicable to thumbnail, so strip it.\n filename = path.parse(item.filename).name;\n }\n const videoThumbnailMediaItem: DummyMediaItem = {\n type: 'dummy',\n id: item.id,\n filename,\n mimeType: null,\n srcURLs: {\n thumbnail: item.displayURLs.thumbnail\n }\n };\n const __config = {\n ...config,\n include: {\n ...config.include,\n allMediaVariants: true // Ensure variant name ('thumbnail') appears in dest filename\n }\n };\n tasks.push(\n ...await this.createFromDownloadable({\n config: __config,\n item: videoThumbnailMediaItem,\n destDir,\n fetcher,\n fileExistsAction,\n callbacks,\n limiter,\n signal,\n logger\n })\n );\n }\n\n if (tasks.length === 0) {\n throw Error('No src URL found');\n }\n\n return tasks;\n }\n\n static #pickVariant(urls: Record<string, any>, priority: string[]) {\n for (const variant of priority) {\n if (urls[variant]) {\n return {\n [variant]: urls[variant]\n };\n }\n }\n return {};\n }\n\n static findEmbedDownloader(edl: EmbedDownloader[], provider?: string | null) {\n return edl.find((dl) => dl.provider.toLowerCase() === provider?.trim().toLowerCase());\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function isYouTubeEmbed(embed) {
|
|
2
|
-
return embed.
|
|
2
|
+
return embed.provider === 'YouTube';
|
|
3
3
|
}
|
|
4
4
|
export function isEmbed(data) {
|
|
5
5
|
return data.type === 'videoEmbed' || data.type === 'linkEmbed' || data.type === 'unknownEmbed';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Downloadable.js","sourceRoot":"","sources":["../../src/entities/Downloadable.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"Downloadable.js","sourceRoot":"","sources":["../../src/entities/Downloadable.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAkB;IACxC,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC;AACjG,CAAC","sourcesContent":["import { type MediaItem } from './MediaItem.js';\nimport { type PostEmbed, type YouTubePostEmbed } from './Post.js';\n\nexport type Downloadable = MediaItem | PostEmbed;\n\nexport function isYouTubeEmbed(embed: PostEmbed): embed is YouTubePostEmbed {\n return embed.provider === 'YouTube';\n}\n\nexport function isEmbed(data: Downloadable): data is PostEmbed {\n return data.type === 'videoEmbed' || data.type === 'linkEmbed' || data.type === 'unknownEmbed';\n}\n"]}
|
package/dist/entities/Post.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Post.d.ts","sourceRoot":"","sources":["../../src/entities/Post.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;;;;;;;OAaG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,KAAK,EAAE,IAAI,EAAE,CAAC;IAEd;;;OAGG;IACH,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAExB;;;OAGG;IACH,WAAW,EAAE,YAAY,EAAE,CAAC;IAE5B;;;OAGG;IACH,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAE3B;;;OAGG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAElC;;;OAGG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;IAEvB;;;;OAIG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAElC;;;;;OAKG;IACH,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAE3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAE1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,GAAG,MAAM,QAAQ,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;IAClD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG;IAAE,
|
|
1
|
+
{"version":3,"file":"Post.d.ts","sourceRoot":"","sources":["../../src/entities/Post.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;;;;;;;OAaG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,KAAK,EAAE,IAAI,EAAE,CAAC;IAEd;;;OAGG;IACH,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IAExB;;;OAGG;IACH,WAAW,EAAE,YAAY,EAAE,CAAC;IAE5B;;;OAGG;IACH,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAE3B;;;OAGG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAElC;;;OAGG;IACH,MAAM,EAAE,YAAY,EAAE,CAAC;IAEvB;;;;OAIG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAElC;;;;;OAKG;IACH,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAE3B,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAE1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,GAAG,MAAM,QAAQ,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;IAClD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Post.js","sourceRoot":"","sources":["../../src/entities/Post.ts"],"names":[],"mappings":"","sourcesContent":["import { type Campaign } from './Campaign.js';\nimport { type Downloadable } from './Downloadable.js';\nimport { type PostCoverImageMediaItem, type PostThumbnailMediaItem } from './MediaItem.js';\nimport { type Tier } from './Reward.js';\n\nexport interface PostCollection {\n url: string;\n posts: Post[];\n total: number | null;\n nextURL: string | null;\n}\n\nexport interface Post {\n type: 'post';\n id: string;\n /**\n * @privateRemarks\n *\n * `data.attibutes.post_type`\n *\n * Known types:\n * - image_file\n * - video_external_file\n * - audio_file\n * - text_only\n * - poll\n * - link: only embedded link info is saved. Link is not followed / downloaded.\n * - video_embed - only embedded video info is saved. Video itself is not downloaded.\n */\n postType: string;\n isViewable: boolean;\n url: string | null;\n title: string | null;\n content: string | null;\n teaserText: string | null;\n publishedAt: string | null;\n editedAt: string | null;\n coverImage: PostCoverImageMediaItem | null;\n thumbnail: PostThumbnailMediaItem | null;\n tiers: Tier[];\n\n /**\n * @privateRemarks\n * `data.attibutes.embed`\n */\n embed: PostEmbed | null;\n\n /**\n * @privateRemarks\n * `data.relationships.attachments`\n */\n attachments: Downloadable[];\n\n /**\n * @privateRemarks\n * `data.relationships.audio`\n */\n audio: Downloadable | null;\n\n /**\n * @privateRemarks\n * `data.relationships.audio_prevew`\n */\n audioPreview: Downloadable | null;\n\n /**\n * @privateRemarks\n * `data.relationships.images`\n */\n images: Downloadable[];\n\n /**\n * @privateRemarks\n * Not included in `data.relationships`\n * Converted from `data.attributes.video_preview`\n */\n videoPreview: Downloadable | null;\n\n /**\n * @privateRemarks\n * Not included in `data.relationships`\n * Converted from `data.attributes.post_file` with\n * `data.attributes.post_type` matching 'video_external_file'\n */\n video: Downloadable | null;\n\n campaign: Campaign | null;\n\n raw: object;\n}\n\nexport interface PostEmbed {\n id: `${string}-embed`;\n postId: string;\n type: 'videoEmbed' | 'linkEmbed' | 'unknownEmbed';\n description: string | null;\n html: string | null;\n provider: string | null;\n providerURL: string | null;\n subject: string | null;\n url: string | null;\n}\n\nexport type YouTubePostEmbed = PostEmbed & {
|
|
1
|
+
{"version":3,"file":"Post.js","sourceRoot":"","sources":["../../src/entities/Post.ts"],"names":[],"mappings":"","sourcesContent":["import { type Campaign } from './Campaign.js';\nimport { type Downloadable } from './Downloadable.js';\nimport { type PostCoverImageMediaItem, type PostThumbnailMediaItem } from './MediaItem.js';\nimport { type Tier } from './Reward.js';\n\nexport interface PostCollection {\n url: string;\n posts: Post[];\n total: number | null;\n nextURL: string | null;\n}\n\nexport interface Post {\n type: 'post';\n id: string;\n /**\n * @privateRemarks\n *\n * `data.attibutes.post_type`\n *\n * Known types:\n * - image_file\n * - video_external_file\n * - audio_file\n * - text_only\n * - poll\n * - link: only embedded link info is saved. Link is not followed / downloaded.\n * - video_embed - only embedded video info is saved. Video itself is not downloaded.\n */\n postType: string;\n isViewable: boolean;\n url: string | null;\n title: string | null;\n content: string | null;\n teaserText: string | null;\n publishedAt: string | null;\n editedAt: string | null;\n coverImage: PostCoverImageMediaItem | null;\n thumbnail: PostThumbnailMediaItem | null;\n tiers: Tier[];\n\n /**\n * @privateRemarks\n * `data.attibutes.embed`\n */\n embed: PostEmbed | null;\n\n /**\n * @privateRemarks\n * `data.relationships.attachments`\n */\n attachments: Downloadable[];\n\n /**\n * @privateRemarks\n * `data.relationships.audio`\n */\n audio: Downloadable | null;\n\n /**\n * @privateRemarks\n * `data.relationships.audio_prevew`\n */\n audioPreview: Downloadable | null;\n\n /**\n * @privateRemarks\n * `data.relationships.images`\n */\n images: Downloadable[];\n\n /**\n * @privateRemarks\n * Not included in `data.relationships`\n * Converted from `data.attributes.video_preview`\n */\n videoPreview: Downloadable | null;\n\n /**\n * @privateRemarks\n * Not included in `data.relationships`\n * Converted from `data.attributes.post_file` with\n * `data.attributes.post_type` matching 'video_external_file'\n */\n video: Downloadable | null;\n\n campaign: Campaign | null;\n\n raw: object;\n}\n\nexport interface PostEmbed {\n id: `${string}-embed`;\n postId: string;\n type: 'videoEmbed' | 'linkEmbed' | 'unknownEmbed';\n description: string | null;\n html: string | null;\n provider: string | null;\n providerURL: string | null;\n subject: string | null;\n url: string | null;\n}\n\nexport type YouTubePostEmbed = PostEmbed & { provider: 'YouTube' }\n"]}
|
|
@@ -10,7 +10,7 @@ export default abstract class FilenameResolver<T> {
|
|
|
10
10
|
protected srcURL: string;
|
|
11
11
|
constructor(target: T, srcURL: string);
|
|
12
12
|
abstract resolve(response: Response): string;
|
|
13
|
-
protected getFilenamePartsFromResponse(response: Response): {
|
|
13
|
+
protected getFilenamePartsFromResponse(response: Response, extByContentType?: boolean): {
|
|
14
14
|
name: string;
|
|
15
15
|
ext: string;
|
|
16
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FllenameResolver.d.ts","sourceRoot":"","sources":["../../src/utils/FllenameResolver.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,gBAAgB,CAAC,CAAC;IAE9C,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACpB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM;IAKrC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM;IAE5C,SAAS,CAAC,4BAA4B,CAAC,QAAQ,EAAE,QAAQ;;;;
|
|
1
|
+
{"version":3,"file":"FllenameResolver.d.ts","sourceRoot":"","sources":["../../src/utils/FllenameResolver.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,gBAAgB,CAAC,CAAC;IAE9C,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACpB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM;IAKrC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM;IAE5C,SAAS,CAAC,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,UAAO;;;;IA+BlF,SAAS,CAAC,yBAAyB,CAAC,IAAI,EAAE,MAAM;CAuBjD"}
|
|
@@ -14,7 +14,7 @@ export default class FilenameResolver {
|
|
|
14
14
|
this.target = target;
|
|
15
15
|
this.srcURL = srcURL;
|
|
16
16
|
}
|
|
17
|
-
getFilenamePartsFromResponse(response) {
|
|
17
|
+
getFilenamePartsFromResponse(response, extByContentType = true) {
|
|
18
18
|
const parts = {
|
|
19
19
|
name: '',
|
|
20
20
|
ext: ''
|
|
@@ -30,12 +30,14 @@ export default class FilenameResolver {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
// Filename obtained from content-disposition could have wrong extension.
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
// The default behavior is to obtain extension from content-type header if available.
|
|
34
|
+
if (extByContentType) {
|
|
35
|
+
const contentType = response.headers.get('content-type') || null;
|
|
36
|
+
if (contentType) {
|
|
37
|
+
const _extByContentType = this.getExtensionByContentType(contentType);
|
|
38
|
+
if (_extByContentType) {
|
|
39
|
+
parts.ext = _extByContentType;
|
|
40
|
+
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
return parts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FllenameResolver.js","sourceRoot":"","sources":["../../src/utils/FllenameResolver.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,qBAAqB,CAAC;AACrD,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAEvC;;;;;;GAMG;AAEH,MAAM,CAAC,OAAO,OAAgB,gBAAgB;IAK5C,YAAY,MAAS,EAAE,MAAc;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAIS,4BAA4B,CAAC,QAAkB;
|
|
1
|
+
{"version":3,"file":"FllenameResolver.js","sourceRoot":"","sources":["../../src/utils/FllenameResolver.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,qBAAqB,CAAC;AACrD,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,SAAS,MAAM,gBAAgB,CAAC;AAEvC;;;;;;GAMG;AAEH,MAAM,CAAC,OAAO,OAAgB,gBAAgB;IAK5C,YAAY,MAAS,EAAE,MAAc;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAIS,4BAA4B,CAAC,QAAkB,EAAE,gBAAgB,GAAG,IAAI;QAChF,MAAM,KAAK,GAAG;YACZ,IAAI,EAAE,EAAE;YACR,GAAG,EAAE,EAAE;SACR,CAAC;QAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAChE,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAChE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC;YAClE,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACpC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACzB,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;YACzB,CAAC;QACH,CAAC;QACD,yEAAyE;QACzE,qFAAqF;QACrF,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC;YACjE,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,iBAAiB,GAAG,IAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;gBACtE,IAAI,iBAAiB,EAAE,CAAC;oBACtB,KAAK,CAAC,GAAG,GAAG,iBAAiB,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAES,yBAAyB,CAAC,IAAY;QAC9C,MAAM,cAAc,GAAG;YACrB,0BAA0B;YAC1B,YAAY;SACb,CAAC;QACF,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,UAAU,GAAG,SAAS,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9D,wDAAwD;QACxD,IAAI,IAAI,KAAK,uBAAuB,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;YAC/D,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,+DAA+D;aAC1D,IAAI,IAAI,KAAK,YAAY,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;YACxD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YACnB,GAAG,GAAG,KAAK,CAAC;QACd,CAAC;QACD,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,CAAC;CACF","sourcesContent":["import contentDisposition from 'content-disposition';\nimport mimeTypes from 'mime-types';\nimport path from 'path';\nimport URLHelper from './URLHelper.js';\n\n/**\n * Used by `Fetcher.download()` to resolve the destination filename\n * of the downloaded item. The resolver implementation depends on the\n * type of target being downloaded. `resolve()` is called with the\n * `Response` object fetched by `Fetcher`, since filename resolution could\n * use data provided in the response headers.\n */\n\nexport default abstract class FilenameResolver<T> {\n\n protected target: T;\n protected srcURL: string;\n\n constructor(target: T, srcURL: string) {\n this.target = target;\n this.srcURL = srcURL;\n }\n\n abstract resolve(response: Response): string;\n\n protected getFilenamePartsFromResponse(response: Response, extByContentType = true) {\n const parts = {\n name: '',\n ext: ''\n };\n\n const disposition = response.headers.get('content-disposition');\n if (disposition) {\n const parsedDisposition = contentDisposition.parse(disposition);\n const filename = parsedDisposition.parameters['filename'] || null;\n if (filename) {\n const parsed = path.parse(filename);\n parts.name = parsed.name;\n parts.ext = parsed.ext;\n }\n }\n // Filename obtained from content-disposition could have wrong extension.\n // The default behavior is to obtain extension from content-type header if available.\n if (extByContentType) {\n const contentType = response.headers.get('content-type') || null;\n if (contentType) {\n const _extByContentType = this.getExtensionByContentType(contentType);\n if (_extByContentType) {\n parts.ext = _extByContentType;\n }\n }\n }\n\n return parts;\n }\n\n protected getExtensionByContentType(type: string) {\n const undeterminable = [\n 'application/octet-stream',\n 'text/plain'\n ];\n if (undeterminable.find((v) => type.includes(v))) {\n return '';\n }\n const extFromURL = URLHelper.getExtensionFromURL(this.srcURL);\n // Mime-types does not recognize 'application/x-mpegURL'\n if (type === 'application/x-mpegURL' && extFromURL === '.m3u8') {\n return '.m3u8';\n }\n // Mime-types returns '.mpga' for 'audio/mpeg' - we want '.mp3'\n else if (type === 'audio/mpeg' && extFromURL === '.mp3') {\n return '.mp3';\n }\n let ext = mimeTypes.extension(type);\n if (ext === 'jpeg') {\n ext = 'jpg';\n }\n return ext ? `.${ext}` : '';\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaFilenameResolver.d.ts","sourceRoot":"","sources":["../../src/utils/MediaFilenameResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AAIrD,MAAM,CAAC,OAAO,OAAO,qBAAqB,CAAC,CAAC,SAAS,SAAS,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;;gBAK7E,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,aAAa,EAAE,OAAO;IAUrG,OAAO,CAAC,QAAQ,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"MediaFilenameResolver.d.ts","sourceRoot":"","sources":["../../src/utils/MediaFilenameResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AAIrD,MAAM,CAAC,OAAO,OAAO,qBAAqB,CAAC,CAAC,SAAS,SAAS,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;;gBAK7E,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,aAAa,EAAE,OAAO;IAUrG,OAAO,CAAC,QAAQ,EAAE,QAAQ;CAiE3B"}
|
|
@@ -28,7 +28,7 @@ class MediaFilenameResolver extends FilenameResolver {
|
|
|
28
28
|
resolve(response) {
|
|
29
29
|
const mi = this.target;
|
|
30
30
|
const miFilenameParts = mi.filename ? path.parse(mi.filename) : null;
|
|
31
|
-
const resFilenameParts = this.getFilenamePartsFromResponse(response);
|
|
31
|
+
const resFilenameParts = this.getFilenamePartsFromResponse(response, mi.type !== 'attachment');
|
|
32
32
|
const filenameParts = {
|
|
33
33
|
name: '',
|
|
34
34
|
ext: ''
|
|
@@ -50,12 +50,15 @@ class MediaFilenameResolver extends FilenameResolver {
|
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Obtain `extension` from (in order of priority):
|
|
53
|
-
* 1. Response headers
|
|
53
|
+
* 1. Response headers (unless target is attachment, in which case (2) takes precedence)
|
|
54
54
|
* 2. Media filename
|
|
55
55
|
* 3. Media mimetype
|
|
56
56
|
* 4. Src URL
|
|
57
57
|
*/
|
|
58
|
-
if (
|
|
58
|
+
if (mi.type === 'attachment' && miFilenameParts?.ext) {
|
|
59
|
+
filenameParts.ext = miFilenameParts.ext;
|
|
60
|
+
}
|
|
61
|
+
else if (resFilenameParts.ext) {
|
|
59
62
|
// Use media item filename if the same (preserves case)
|
|
60
63
|
if (miFilenameParts?.ext?.toLowerCase() === resFilenameParts.ext.toLowerCase() &&
|
|
61
64
|
filenameParts.name === miFilenameParts.name && __classPrivateFieldGet(this, _MediaFilenameResolver_format, "f").includes('{media.filename}')) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaFilenameResolver.js","sourceRoot":"","sources":["../../src/utils/MediaFilenameResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AACrD,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAE7D,MAAqB,qBAA2C,SAAQ,gBAAmB;IAKzF,YAAY,MAAS,EAAE,MAAc,EAAE,MAAc,EAAE,OAAsB,EAAE,aAAsB;QACnG,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAJxB,gDAAgB;QAChB,iDAAwB;QAItB,uBAAA,IAAI,iCAAW,MAAM,MAAA,CAAC;QACtB,uBAAA,IAAI,kCAAY,OAAO,MAAA,CAAC;QAExB,IAAI,aAAa,IAAI,CAAC,uBAAA,IAAI,qCAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC/D,uBAAA,IAAI,iCAAW,GAAG,MAAM,qBAAqB,MAAA,CAAC;QAChD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,QAAkB;QACxB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACvB,MAAM,eAAe,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,MAAM,gBAAgB,GAAG,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaFilenameResolver.js","sourceRoot":"","sources":["../../src/utils/MediaFilenameResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'path';\nimport { type MediaLike } from '../entities/MediaItem.js';\nimport FilenameResolver from './FllenameResolver.js';\nimport URLHelper from './URLHelper.js';\nimport FilenameFormatHelper from './FilenameFormatHelper.js';\n\nexport default class MediaFilenameResolver<T extends MediaLike> extends FilenameResolver<T> {\n\n #format: string;\n #variant: string | null;\n\n constructor(target: T, srcURL: string, format: string, variant: string | null, ensureVariant: boolean) {\n super(target, srcURL);\n this.#format = format;\n this.#variant = variant;\n\n if (ensureVariant && !this.#format.includes('{media.variant}')) {\n this.#format = `${format}[-]?{media.variant}`;\n }\n }\n\n resolve(response: Response) {\n const mi = this.target;\n const miFilenameParts = mi.filename ? path.parse(mi.filename) : null;\n const resFilenameParts = this.getFilenamePartsFromResponse(response, mi.type !== 'attachment');\n\n const filenameParts = {\n name: '',\n ext: ''\n };\n\n /**\n * Obtain `name` part from (in order of priority):\n * 1. Media filename\n * 2. Filename from response headers\n * 3. If none of the above is available, fallback to using the media ID\n */\n if (miFilenameParts?.name) {\n filenameParts.name = miFilenameParts.name;\n }\n else if (resFilenameParts.name) {\n filenameParts.name = resFilenameParts.name;\n }\n else if (!this.#format.includes('{media.id}')) {\n filenameParts.name = mi.id;\n }\n\n /**\n * Obtain `extension` from (in order of priority):\n * 1. Response headers (unless target is attachment, in which case (2) takes precedence)\n * 2. Media filename\n * 3. Media mimetype\n * 4. Src URL\n */\n if (mi.type === 'attachment' && miFilenameParts?.ext) {\n filenameParts.ext = miFilenameParts.ext;\n }\n else if (resFilenameParts.ext) {\n // Use media item filename if the same (preserves case)\n if (miFilenameParts?.ext?.toLowerCase() === resFilenameParts.ext.toLowerCase() &&\n filenameParts.name === miFilenameParts.name && this.#format.includes('{media.filename}')) {\n\n filenameParts.ext = miFilenameParts.ext;\n }\n else {\n filenameParts.ext = resFilenameParts.ext;\n }\n }\n else if (miFilenameParts?.ext) {\n filenameParts.ext = miFilenameParts.ext;\n }\n else if (mi.mimeType) {\n filenameParts.ext = this.getExtensionByContentType(mi.mimeType);\n }\n else {\n filenameParts.ext = URLHelper.getExtensionFromURL(this.srcURL);\n }\n\n const tmpMI = {\n ...mi,\n filename: filenameParts.name,\n variant: this.#variant\n };\n\n return FilenameFormatHelper.getMediaFilename(tmpMI, this.#format, filenameParts.ext);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patreon-dl",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Patreon Downloader",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./dist/index.js",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"speedometer": "^1.1.0",
|
|
85
85
|
"string-argv": "^0.3.2",
|
|
86
86
|
"yargs-parser": "^21.1.1",
|
|
87
|
-
"youtubei.js": "^12.
|
|
87
|
+
"youtubei.js": "^12.2.0"
|
|
88
88
|
},
|
|
89
89
|
"keywords": [
|
|
90
90
|
"patreon",
|