patreon-dl 1.0.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.
Files changed (223) hide show
  1. package/README.md +422 -0
  2. package/bin/patreon-dl.js +5 -0
  3. package/dist/cli/CLIOptionValidator.d.ts +9 -0
  4. package/dist/cli/CLIOptionValidator.d.ts.map +1 -0
  5. package/dist/cli/CLIOptionValidator.js +85 -0
  6. package/dist/cli/CLIOptionValidator.js.map +1 -0
  7. package/dist/cli/CLIOptions.d.ts +20 -0
  8. package/dist/cli/CLIOptions.d.ts.map +1 -0
  9. package/dist/cli/CLIOptions.js +75 -0
  10. package/dist/cli/CLIOptions.js.map +1 -0
  11. package/dist/cli/CommandLineParser.d.ts +11 -0
  12. package/dist/cli/CommandLineParser.d.ts.map +1 -0
  13. package/dist/cli/CommandLineParser.js +212 -0
  14. package/dist/cli/CommandLineParser.js.map +1 -0
  15. package/dist/cli/ConfigFileParser.d.ts +9 -0
  16. package/dist/cli/ConfigFileParser.d.ts.map +1 -0
  17. package/dist/cli/ConfigFileParser.js +163 -0
  18. package/dist/cli/ConfigFileParser.js.map +1 -0
  19. package/dist/cli/index.d.ts +7 -0
  20. package/dist/cli/index.d.ts.map +1 -0
  21. package/dist/cli/index.js +162 -0
  22. package/dist/cli/index.js.map +1 -0
  23. package/dist/downloaders/Bootstrap.d.ts +29 -0
  24. package/dist/downloaders/Bootstrap.d.ts.map +1 -0
  25. package/dist/downloaders/Bootstrap.js +51 -0
  26. package/dist/downloaders/Bootstrap.js.map +1 -0
  27. package/dist/downloaders/Downloader.d.ts +59 -0
  28. package/dist/downloaders/Downloader.d.ts.map +1 -0
  29. package/dist/downloaders/Downloader.js +357 -0
  30. package/dist/downloaders/Downloader.js.map +1 -0
  31. package/dist/downloaders/DownloaderEvent.d.ts +47 -0
  32. package/dist/downloaders/DownloaderEvent.d.ts.map +1 -0
  33. package/dist/downloaders/DownloaderEvent.js +6 -0
  34. package/dist/downloaders/DownloaderEvent.js.map +1 -0
  35. package/dist/downloaders/DownloaderOptions.d.ts +39 -0
  36. package/dist/downloaders/DownloaderOptions.d.ts.map +1 -0
  37. package/dist/downloaders/DownloaderOptions.js +69 -0
  38. package/dist/downloaders/DownloaderOptions.js.map +1 -0
  39. package/dist/downloaders/PostDownloader.d.ts +8 -0
  40. package/dist/downloaders/PostDownloader.d.ts.map +1 -0
  41. package/dist/downloaders/PostDownloader.js +428 -0
  42. package/dist/downloaders/PostDownloader.js.map +1 -0
  43. package/dist/downloaders/ProductDownloader.d.ts +8 -0
  44. package/dist/downloaders/ProductDownloader.d.ts.map +1 -0
  45. package/dist/downloaders/ProductDownloader.js +171 -0
  46. package/dist/downloaders/ProductDownloader.js.map +1 -0
  47. package/dist/downloaders/cache/StatusCache.d.ts +43 -0
  48. package/dist/downloaders/cache/StatusCache.d.ts.map +1 -0
  49. package/dist/downloaders/cache/StatusCache.js +206 -0
  50. package/dist/downloaders/cache/StatusCache.js.map +1 -0
  51. package/dist/downloaders/index.d.ts +7 -0
  52. package/dist/downloaders/index.d.ts.map +1 -0
  53. package/dist/downloaders/index.js +6 -0
  54. package/dist/downloaders/index.js.map +1 -0
  55. package/dist/downloaders/task/DownloadTask.d.ts +89 -0
  56. package/dist/downloaders/task/DownloadTask.d.ts.map +1 -0
  57. package/dist/downloaders/task/DownloadTask.js +240 -0
  58. package/dist/downloaders/task/DownloadTask.js.map +1 -0
  59. package/dist/downloaders/task/DownloadTaskBatch.d.ts +45 -0
  60. package/dist/downloaders/task/DownloadTaskBatch.d.ts.map +1 -0
  61. package/dist/downloaders/task/DownloadTaskBatch.js +195 -0
  62. package/dist/downloaders/task/DownloadTaskBatch.js.map +1 -0
  63. package/dist/downloaders/task/DownloadTaskBatchEvent.d.ts +32 -0
  64. package/dist/downloaders/task/DownloadTaskBatchEvent.d.ts.map +1 -0
  65. package/dist/downloaders/task/DownloadTaskBatchEvent.js +2 -0
  66. package/dist/downloaders/task/DownloadTaskBatchEvent.js.map +1 -0
  67. package/dist/downloaders/task/DownloadTaskFactory.d.ts +20 -0
  68. package/dist/downloaders/task/DownloadTaskFactory.d.ts.map +1 -0
  69. package/dist/downloaders/task/DownloadTaskFactory.js +177 -0
  70. package/dist/downloaders/task/DownloadTaskFactory.js.map +1 -0
  71. package/dist/downloaders/task/FFmpegDownloadTask.d.ts +27 -0
  72. package/dist/downloaders/task/FFmpegDownloadTask.d.ts.map +1 -0
  73. package/dist/downloaders/task/FFmpegDownloadTask.js +206 -0
  74. package/dist/downloaders/task/FFmpegDownloadTask.js.map +1 -0
  75. package/dist/downloaders/task/FetcherDownloadTask.d.ts +21 -0
  76. package/dist/downloaders/task/FetcherDownloadTask.d.ts.map +1 -0
  77. package/dist/downloaders/task/FetcherDownloadTask.js +213 -0
  78. package/dist/downloaders/task/FetcherDownloadTask.js.map +1 -0
  79. package/dist/downloaders/task/index.d.ts +4 -0
  80. package/dist/downloaders/task/index.d.ts.map +1 -0
  81. package/dist/downloaders/task/index.js +3 -0
  82. package/dist/downloaders/task/index.js.map +1 -0
  83. package/dist/downloaders/templates/CampaignInfo.d.ts +3 -0
  84. package/dist/downloaders/templates/CampaignInfo.d.ts.map +1 -0
  85. package/dist/downloaders/templates/CampaignInfo.js +58 -0
  86. package/dist/downloaders/templates/CampaignInfo.js.map +1 -0
  87. package/dist/downloaders/templates/PostInfo.d.ts +4 -0
  88. package/dist/downloaders/templates/PostInfo.d.ts.map +1 -0
  89. package/dist/downloaders/templates/PostInfo.js +45 -0
  90. package/dist/downloaders/templates/PostInfo.js.map +1 -0
  91. package/dist/downloaders/templates/ProductInfo.d.ts +3 -0
  92. package/dist/downloaders/templates/ProductInfo.d.ts.map +1 -0
  93. package/dist/downloaders/templates/ProductInfo.js +20 -0
  94. package/dist/downloaders/templates/ProductInfo.js.map +1 -0
  95. package/dist/entities/Attachment.d.ts +7 -0
  96. package/dist/entities/Attachment.d.ts.map +1 -0
  97. package/dist/entities/Attachment.js +2 -0
  98. package/dist/entities/Attachment.js.map +1 -0
  99. package/dist/entities/Campaign.d.ts +19 -0
  100. package/dist/entities/Campaign.d.ts.map +1 -0
  101. package/dist/entities/Campaign.js +2 -0
  102. package/dist/entities/Campaign.js.map +1 -0
  103. package/dist/entities/Downloadable.d.ts +6 -0
  104. package/dist/entities/Downloadable.d.ts.map +1 -0
  105. package/dist/entities/Downloadable.js +5 -0
  106. package/dist/entities/Downloadable.js.map +1 -0
  107. package/dist/entities/MediaItem.d.ts +95 -0
  108. package/dist/entities/MediaItem.d.ts.map +1 -0
  109. package/dist/entities/MediaItem.js +2 -0
  110. package/dist/entities/MediaItem.js.map +1 -0
  111. package/dist/entities/Post.d.ts +87 -0
  112. package/dist/entities/Post.d.ts.map +1 -0
  113. package/dist/entities/Post.js +2 -0
  114. package/dist/entities/Post.js.map +1 -0
  115. package/dist/entities/Product.d.ts +17 -0
  116. package/dist/entities/Product.d.ts.map +1 -0
  117. package/dist/entities/Product.js +2 -0
  118. package/dist/entities/Product.js.map +1 -0
  119. package/dist/entities/Reward.d.ts +14 -0
  120. package/dist/entities/Reward.d.ts.map +1 -0
  121. package/dist/entities/Reward.js +2 -0
  122. package/dist/entities/Reward.js.map +1 -0
  123. package/dist/entities/User.d.ts +15 -0
  124. package/dist/entities/User.d.ts.map +1 -0
  125. package/dist/entities/User.js +2 -0
  126. package/dist/entities/User.js.map +1 -0
  127. package/dist/entities/index.d.ts +9 -0
  128. package/dist/entities/index.d.ts.map +1 -0
  129. package/dist/entities/index.js +6 -0
  130. package/dist/entities/index.js.map +1 -0
  131. package/dist/index.d.ts +8 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +8 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/parsers/PageParser.d.ts +6 -0
  136. package/dist/parsers/PageParser.d.ts.map +1 -0
  137. package/dist/parsers/PageParser.js +23 -0
  138. package/dist/parsers/PageParser.js.map +1 -0
  139. package/dist/parsers/Parser.d.ts +43 -0
  140. package/dist/parsers/Parser.d.ts.map +1 -0
  141. package/dist/parsers/Parser.js +439 -0
  142. package/dist/parsers/Parser.js.map +1 -0
  143. package/dist/parsers/PostParser.d.ts +7 -0
  144. package/dist/parsers/PostParser.d.ts.map +1 -0
  145. package/dist/parsers/PostParser.js +259 -0
  146. package/dist/parsers/PostParser.js.map +1 -0
  147. package/dist/parsers/ProductParser.d.ts +7 -0
  148. package/dist/parsers/ProductParser.d.ts.map +1 -0
  149. package/dist/parsers/ProductParser.js +70 -0
  150. package/dist/parsers/ProductParser.js.map +1 -0
  151. package/dist/utils/AttachmentFilenameResolver.d.ts +9 -0
  152. package/dist/utils/AttachmentFilenameResolver.d.ts.map +1 -0
  153. package/dist/utils/AttachmentFilenameResolver.js +73 -0
  154. package/dist/utils/AttachmentFilenameResolver.js.map +1 -0
  155. package/dist/utils/FSHelper.d.ts +57 -0
  156. package/dist/utils/FSHelper.d.ts.map +1 -0
  157. package/dist/utils/FSHelper.js +214 -0
  158. package/dist/utils/FSHelper.js.map +1 -0
  159. package/dist/utils/Fetcher.d.ts +45 -0
  160. package/dist/utils/Fetcher.d.ts.map +1 -0
  161. package/dist/utils/Fetcher.js +192 -0
  162. package/dist/utils/Fetcher.js.map +1 -0
  163. package/dist/utils/FetcherProgressMonitor.d.ts +18 -0
  164. package/dist/utils/FetcherProgressMonitor.d.ts.map +1 -0
  165. package/dist/utils/FetcherProgressMonitor.js +56 -0
  166. package/dist/utils/FetcherProgressMonitor.js.map +1 -0
  167. package/dist/utils/FilenameFormatHelper.d.ts +44 -0
  168. package/dist/utils/FilenameFormatHelper.d.ts.map +1 -0
  169. package/dist/utils/FilenameFormatHelper.js +98 -0
  170. package/dist/utils/FilenameFormatHelper.js.map +1 -0
  171. package/dist/utils/FllenameResolver.d.ts +20 -0
  172. package/dist/utils/FllenameResolver.d.ts.map +1 -0
  173. package/dist/utils/FllenameResolver.js +55 -0
  174. package/dist/utils/FllenameResolver.js.map +1 -0
  175. package/dist/utils/Formatter.d.ts +21 -0
  176. package/dist/utils/Formatter.d.ts.map +1 -0
  177. package/dist/utils/Formatter.js +112 -0
  178. package/dist/utils/Formatter.js.map +1 -0
  179. package/dist/utils/MediaFilenameResolver.d.ts +9 -0
  180. package/dist/utils/MediaFilenameResolver.d.ts.map +1 -0
  181. package/dist/utils/MediaFilenameResolver.js +90 -0
  182. package/dist/utils/MediaFilenameResolver.js.map +1 -0
  183. package/dist/utils/Misc.d.ts +14 -0
  184. package/dist/utils/Misc.d.ts.map +1 -0
  185. package/dist/utils/Misc.js +4 -0
  186. package/dist/utils/Misc.js.map +1 -0
  187. package/dist/utils/ObjectHelper.d.ts +4 -0
  188. package/dist/utils/ObjectHelper.d.ts.map +1 -0
  189. package/dist/utils/ObjectHelper.js +30 -0
  190. package/dist/utils/ObjectHelper.js.map +1 -0
  191. package/dist/utils/PackageInfo.d.ts +10 -0
  192. package/dist/utils/PackageInfo.d.ts.map +1 -0
  193. package/dist/utils/PackageInfo.js +33 -0
  194. package/dist/utils/PackageInfo.js.map +1 -0
  195. package/dist/utils/URLHelper.d.ts +40 -0
  196. package/dist/utils/URLHelper.d.ts.map +1 -0
  197. package/dist/utils/URLHelper.js +192 -0
  198. package/dist/utils/URLHelper.js.map +1 -0
  199. package/dist/utils/index.d.ts +2 -0
  200. package/dist/utils/index.d.ts.map +1 -0
  201. package/dist/utils/index.js +2 -0
  202. package/dist/utils/index.js.map +1 -0
  203. package/dist/utils/logging/ChainLogger.d.ts +11 -0
  204. package/dist/utils/logging/ChainLogger.d.ts.map +1 -0
  205. package/dist/utils/logging/ChainLogger.js +50 -0
  206. package/dist/utils/logging/ChainLogger.js.map +1 -0
  207. package/dist/utils/logging/ConsoleLogger.d.ts +31 -0
  208. package/dist/utils/logging/ConsoleLogger.d.ts.map +1 -0
  209. package/dist/utils/logging/ConsoleLogger.js +126 -0
  210. package/dist/utils/logging/ConsoleLogger.js.map +1 -0
  211. package/dist/utils/logging/FileLogger.d.ts +26 -0
  212. package/dist/utils/logging/FileLogger.d.ts.map +1 -0
  213. package/dist/utils/logging/FileLogger.js +147 -0
  214. package/dist/utils/logging/FileLogger.js.map +1 -0
  215. package/dist/utils/logging/Logger.d.ts +12 -0
  216. package/dist/utils/logging/Logger.d.ts.map +1 -0
  217. package/dist/utils/logging/Logger.js +15 -0
  218. package/dist/utils/logging/Logger.js.map +1 -0
  219. package/dist/utils/logging/index.d.ts +7 -0
  220. package/dist/utils/logging/index.d.ts.map +1 -0
  221. package/dist/utils/logging/index.js +7 -0
  222. package/dist/utils/logging/index.js.map +1 -0
  223. package/package.json +78 -0
@@ -0,0 +1,259 @@
1
+ import { pickDefined } from '../utils/Misc.js';
2
+ import ObjectHelper from '../utils/ObjectHelper.js';
3
+ import Parser from './Parser.js';
4
+ export default class PostParser extends Parser {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.name = 'PostParser';
8
+ }
9
+ parsePostsAPIResponse(json, _url) {
10
+ this.log('debug', `Parse API response of "${_url}"`);
11
+ /*If (json.errors) {
12
+ this.log('error', `API response error:`, json.errors);
13
+ return null;
14
+ }*/
15
+ const includedJSON = json.included;
16
+ const dataJSON = json.data;
17
+ let postsJSONArray;
18
+ // Check if API data consists of just a single post (not an array).
19
+ // If so, place the post data in an array.
20
+ if (dataJSON && !Array.isArray(dataJSON) && dataJSON.type === 'post') {
21
+ postsJSONArray = [dataJSON];
22
+ }
23
+ // If API data is an array, filter out those matching 'post' type.
24
+ else if (dataJSON && Array.isArray(dataJSON)) {
25
+ postsJSONArray = dataJSON.filter((data) => data.type === 'post');
26
+ }
27
+ else {
28
+ // No posts found
29
+ postsJSONArray = [];
30
+ }
31
+ const nextURL = ObjectHelper.getProperty(json, 'links.next') || null;
32
+ const nextPageCursor = ObjectHelper.getProperty(json, 'meta.pagination.cursors.next');
33
+ let realNextURL = null;
34
+ if (nextURL && nextPageCursor) {
35
+ const urlObj = new URL(nextURL);
36
+ urlObj.searchParams.set('page[cursor]', nextPageCursor);
37
+ realNextURL = urlObj.toString();
38
+ }
39
+ if (nextURL && !nextPageCursor) {
40
+ this.log('warn', `Anomaly in API response of "${_url}: (pagination) next page cursor expected but missing`);
41
+ }
42
+ const collection = {
43
+ url: _url,
44
+ posts: [],
45
+ total: ObjectHelper.getProperty(json, 'meta.pagination.total') || null,
46
+ nextURL: realNextURL
47
+ };
48
+ let hasIncludedJSON = true;
49
+ if (!includedJSON || !Array.isArray(includedJSON)) {
50
+ this.log('warn', `'included' field missing in API response of "${_url}" or has incorrect type - no media items and campaign info will be returned`);
51
+ hasIncludedJSON = false;
52
+ }
53
+ if (postsJSONArray.length === 0) {
54
+ this.log('warn', `No posts found in API response of "${_url}"`);
55
+ return collection;
56
+ }
57
+ if (postsJSONArray.length > 1) {
58
+ this.log('debug', `${postsJSONArray.length} posts found - iterate and parse`);
59
+ }
60
+ else {
61
+ this.log('debug', '1 post found - parse');
62
+ }
63
+ let campaign;
64
+ for (const postJSON of postsJSONArray) {
65
+ if (!postJSON || typeof postJSON !== 'object') {
66
+ this.log('error', 'Parse error: API data of post has incorrect type');
67
+ continue;
68
+ }
69
+ const { id, attributes, relationships = {} } = postJSON;
70
+ if (!id) {
71
+ this.log('error', 'Parse error: \'id\' field missing in API data of post');
72
+ continue;
73
+ }
74
+ this.log('debug', `Parse post #${id}`);
75
+ if (!attributes || typeof attributes !== 'object') {
76
+ this.log('error', `Parse error: 'attributes' field missing in API data of post #${id} or has incorrect type`);
77
+ continue;
78
+ }
79
+ // Campaign info
80
+ if (campaign === undefined) {
81
+ const campaignId = ObjectHelper.getProperty(postJSON, 'relationships.campaign.data.id') || null;
82
+ if (!campaignId || typeof campaignId !== 'string') {
83
+ this.log('warn', `Campaign ID missing in API data of post #${id} or has incorrect type` +
84
+ ' - no campaign info will be available until campaign ID is obtained');
85
+ }
86
+ else if (hasIncludedJSON) {
87
+ campaign = this.findInAPIResponseIncludedArray(includedJSON, campaignId, 'campaign');
88
+ }
89
+ }
90
+ // Viewability
91
+ const isViewable = pickDefined(attributes.current_user_can_view, true);
92
+ if (attributes.current_user_can_view === undefined) {
93
+ this.log('warn', `'current_user_can_view' attribute missing in API data of post #${id} - assuming post is viewable`);
94
+ }
95
+ // Get downloadables from relationships
96
+ let audio = null;
97
+ let audioPreview = null;
98
+ let images = [];
99
+ let attachments = [];
100
+ if (hasIncludedJSON) {
101
+ const downloadables = this.fetchDownloadablesFromRelationships(relationships, {
102
+ 'audio': 'audio items',
103
+ 'audio_preview': 'audio preview items',
104
+ 'images': 'images',
105
+ 'attachments': 'attachments'
106
+ }, includedJSON, `post #${id}`, false);
107
+ audio = downloadables.audio?.[0] || null;
108
+ audioPreview = downloadables.audio_preview?.[0] || null;
109
+ images = downloadables.images || [];
110
+ attachments = downloadables.attachments || [];
111
+ }
112
+ const __getVideoMediaItemFromAttr = (attrJSON) => {
113
+ let miFromIncluded = null;
114
+ const _mediaId = attrJSON.media_id !== undefined ? attrJSON.media_id.toString() : null;
115
+ if (_mediaId && hasIncludedJSON) {
116
+ // Fetch item from 'included' array, matching `media_id`
117
+ miFromIncluded = this.findInAPIResponseIncludedArray(includedJSON, _mediaId, 'media', 'video');
118
+ }
119
+ const vidInc = miFromIncluded && miFromIncluded.type === 'video' ? miFromIncluded : null;
120
+ const mediaId = _mediaId || id; // Fallback to post ID
121
+ const { download_url: downloadURL = null, url: displayURL = null } = attrJSON;
122
+ // Convert `attrJSON` to Downloadable (VideoMediaItem)
123
+ return {
124
+ type: 'video',
125
+ id: mediaId,
126
+ filename: vidInc?.filename || null,
127
+ mimeType: vidInc?.mimeType || null,
128
+ createdAt: vidInc?.createdAt || null,
129
+ size: {
130
+ width: attrJSON.width || vidInc?.size.width,
131
+ height: attrJSON.height || vidInc?.size.height
132
+ },
133
+ duration: attrJSON.duration || vidInc?.duration,
134
+ downloadURL: downloadURL || vidInc?.downloadURL,
135
+ displayURLs: {
136
+ thumbnail: vidInc?.displayURLs.thumbnail || null,
137
+ video: displayURL || vidInc?.downloadURL
138
+ }
139
+ };
140
+ };
141
+ // Video preview
142
+ let videoPreview = null;
143
+ const vidPreviewJSON = attributes.video_preview;
144
+ if (vidPreviewJSON && typeof vidPreviewJSON === 'object') {
145
+ videoPreview = __getVideoMediaItemFromAttr(vidPreviewJSON);
146
+ if (!videoPreview.downloadURL && !videoPreview.displayURLs.video) {
147
+ this.log('warn', `Video preview for post #${id} is missing URLs`);
148
+ }
149
+ }
150
+ // Video - `postType` is 'video_external_file' and has `postFile`
151
+ let video = null;
152
+ const postFileJSON = attributes.post_file;
153
+ const hasPostFile = postFileJSON && typeof postFileJSON === 'object';
154
+ if (attributes.post_type === 'video_external_file' && hasPostFile) {
155
+ video = __getVideoMediaItemFromAttr(postFileJSON);
156
+ if (!video.downloadURL && !video.displayURLs.video) {
157
+ this.log('warn', `Video for post #${id} is missing URLs`);
158
+ }
159
+ }
160
+ // Cover image
161
+ let coverImage = null;
162
+ if (attributes.image) {
163
+ coverImage = {
164
+ type: 'image',
165
+ id,
166
+ filename: isViewable ? 'cover-image' : 'cover-image-preview',
167
+ mimeType: null,
168
+ imageType: 'postCoverImage',
169
+ imageURLs: {
170
+ large: ObjectHelper.getProperty(attributes, 'image.large_url') || null,
171
+ thumbSquareLarge: ObjectHelper.getProperty(attributes, 'image.thumb_square_large_url') || null,
172
+ thumbSquare: ObjectHelper.getProperty(attributes, 'image.thumb_square_url') || null,
173
+ thumb: ObjectHelper.getProperty(attributes, 'image.thumb_url') || null,
174
+ default: ObjectHelper.getProperty(attributes, 'image.url') || null
175
+ }
176
+ };
177
+ }
178
+ // Thumbnail
179
+ let thumbnail = null;
180
+ if (attributes.thumbnail) {
181
+ thumbnail = {
182
+ type: 'image',
183
+ id,
184
+ filename: isViewable ? 'thumbnail' : 'thumbnail-preview',
185
+ mimeType: null,
186
+ imageType: 'postThumbnail',
187
+ imageURLs: {
188
+ large: ObjectHelper.getProperty(attributes, 'thumbnail.large') || null,
189
+ large2: ObjectHelper.getProperty(attributes, 'thumbnail.large_2') || null,
190
+ square: ObjectHelper.getProperty(attributes, 'thumbnail.square') || null,
191
+ default: ObjectHelper.getProperty(attributes, 'thumbnail.url') || null
192
+ }
193
+ };
194
+ }
195
+ // Embed
196
+ const embedJSON = attributes.embed;
197
+ let embed = null;
198
+ if (embedJSON && typeof embedJSON === 'object') {
199
+ let embedType;
200
+ switch (attributes.post_type) {
201
+ case 'video_embed':
202
+ embedType = 'video';
203
+ break;
204
+ case 'link':
205
+ embedType = 'link';
206
+ break;
207
+ default:
208
+ embedType = 'unknown';
209
+ }
210
+ embed = {
211
+ type: embedType,
212
+ description: embedJSON.descripton || null,
213
+ html: embedJSON.html || null,
214
+ provider: embedJSON.provider || null,
215
+ providerURL: embedJSON.provider_url || null,
216
+ subject: embedJSON.subject || null,
217
+ url: embedJSON.url || null
218
+ };
219
+ }
220
+ const post = {
221
+ id,
222
+ type: 'post',
223
+ postType: attributes.post_type || null,
224
+ isViewable,
225
+ url: attributes.url || null,
226
+ title: attributes.title || null,
227
+ content: attributes.content || null,
228
+ teaserText: attributes.teaser_text || null,
229
+ publishedAt: attributes.published_at || null,
230
+ editedAt: attributes.edited_at || null,
231
+ coverImage,
232
+ thumbnail,
233
+ embed,
234
+ attachments,
235
+ audio,
236
+ audioPreview,
237
+ images,
238
+ videoPreview,
239
+ video,
240
+ campaign: null,
241
+ raw: json
242
+ };
243
+ this.log('debug', `Done parsing post #${id}`);
244
+ collection.posts.push(post);
245
+ }
246
+ if (campaign) {
247
+ this.log('debug', `Campaign #${campaign.id} found while parsing posts`);
248
+ for (const post of collection.posts) {
249
+ post.campaign = campaign;
250
+ }
251
+ }
252
+ else {
253
+ this.log('warn', 'No campaign info found while parsing posts');
254
+ }
255
+ this.log('debug', 'Done parsing posts');
256
+ return collection;
257
+ }
258
+ }
259
+ //# sourceMappingURL=PostParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostParser.js","sourceRoot":"","sources":["../../src/parsers/PostParser.ts"],"names":[],"mappings":"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","sourcesContent":["import { Campaign } from '../entities/Campaign.js';\nimport { Downloadable } from '../entities/Downloadable.js';\nimport { MediaItem, PostCoverImageMediaItem, PostThumbnailMediaItem, VideoMediaItem } from '../entities/MediaItem.js';\nimport { Post, PostCollection, PostEmbed } from '../entities/Post.js';\nimport { pickDefined } from '../utils/Misc.js';\nimport ObjectHelper from '../utils/ObjectHelper.js';\nimport Parser from './Parser.js';\n\nexport default class PostParser extends Parser {\n\n protected name = 'PostParser';\n\n parsePostsAPIResponse(json: any, _url: string): PostCollection {\n\n this.log('debug', `Parse API response of \"${_url}\"`);\n\n /*If (json.errors) {\n this.log('error', `API response error:`, json.errors);\n return null;\n }*/\n\n const includedJSON = json.included;\n const dataJSON = json.data;\n let postsJSONArray: any[];\n // Check if API data consists of just a single post (not an array).\n // If so, place the post data in an array.\n if (dataJSON && !Array.isArray(dataJSON) && dataJSON.type === 'post') {\n postsJSONArray = [ dataJSON ];\n }\n // If API data is an array, filter out those matching 'post' type.\n else if (dataJSON && Array.isArray(dataJSON)) {\n postsJSONArray = dataJSON.filter((data) => data.type === 'post');\n }\n else {\n // No posts found\n postsJSONArray = [];\n }\n\n const nextURL = ObjectHelper.getProperty(json, 'links.next') || null;\n const nextPageCursor = ObjectHelper.getProperty(json, 'meta.pagination.cursors.next');\n let realNextURL: string | null = null;\n if (nextURL && nextPageCursor) {\n const urlObj = new URL(nextURL);\n urlObj.searchParams.set('page[cursor]', nextPageCursor);\n realNextURL = urlObj.toString();\n }\n if (nextURL && !nextPageCursor) {\n this.log('warn', `Anomaly in API response of \"${_url}: (pagination) next page cursor expected but missing`);\n }\n const collection: PostCollection = {\n url: _url,\n posts: [],\n total: ObjectHelper.getProperty(json, 'meta.pagination.total') || null,\n nextURL: realNextURL\n };\n\n let hasIncludedJSON = true;\n if (!includedJSON || !Array.isArray(includedJSON)) {\n this.log('warn', `'included' field missing in API response of \"${_url}\" or has incorrect type - no media items and campaign info will be returned`);\n hasIncludedJSON = false;\n }\n\n if (postsJSONArray.length === 0) {\n this.log('warn', `No posts found in API response of \"${_url}\"`);\n return collection;\n }\n if (postsJSONArray.length > 1) {\n this.log('debug', `${postsJSONArray.length} posts found - iterate and parse`);\n }\n else {\n this.log('debug', '1 post found - parse');\n }\n\n let campaign: Campaign | null | undefined;\n\n for (const postJSON of postsJSONArray) {\n if (!postJSON || typeof postJSON !== 'object') {\n this.log('error', 'Parse error: API data of post has incorrect type');\n continue;\n }\n\n const { id, attributes, relationships = {} } = postJSON;\n\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of post');\n continue;\n }\n\n this.log('debug', `Parse post #${id}`);\n\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of post #${id} or has incorrect type`);\n continue;\n }\n\n // Campaign info\n if (campaign === undefined) {\n const campaignId = ObjectHelper.getProperty(postJSON, 'relationships.campaign.data.id') || null;\n if (!campaignId || typeof campaignId !== 'string') {\n this.log('warn', `Campaign ID missing in API data of post #${id} or has incorrect type` +\n ' - no campaign info will be available until campaign ID is obtained');\n }\n else if (hasIncludedJSON) {\n campaign = this.findInAPIResponseIncludedArray(includedJSON, campaignId, 'campaign');\n }\n }\n\n // Viewability\n const isViewable = pickDefined(attributes.current_user_can_view, true);\n if (attributes.current_user_can_view === undefined) {\n this.log('warn', `'current_user_can_view' attribute missing in API data of post #${id} - assuming post is viewable`);\n }\n\n // Get downloadables from relationships\n let audio: Downloadable | null = null;\n let audioPreview: Downloadable | null = null;\n let images: Downloadable[] = [];\n let attachments: Downloadable[] = [];\n if (hasIncludedJSON) {\n const downloadables = this.fetchDownloadablesFromRelationships(\n relationships,\n {\n 'audio': 'audio items',\n 'audio_preview': 'audio preview items',\n 'images': 'images',\n 'attachments': 'attachments'\n },\n includedJSON,\n `post #${id}`,\n false\n );\n audio = downloadables.audio?.[0] || null;\n audioPreview = downloadables.audio_preview?.[0] || null;\n images = downloadables.images || [];\n attachments = downloadables.attachments || [];\n }\n\n const __getVideoMediaItemFromAttr = (attrJSON: any): VideoMediaItem => {\n let miFromIncluded: MediaItem | null = null;\n const _mediaId = attrJSON.media_id !== undefined ? attrJSON.media_id.toString() : null;\n if (_mediaId && hasIncludedJSON) {\n // Fetch item from 'included' array, matching `media_id`\n miFromIncluded = this.findInAPIResponseIncludedArray(includedJSON, _mediaId, 'media', 'video');\n }\n const vidInc = miFromIncluded && miFromIncluded.type === 'video' ? miFromIncluded : null;\n const mediaId = _mediaId || id; // Fallback to post ID\n\n const { download_url: downloadURL = null, url: displayURL = null } = attrJSON;\n\n // Convert `attrJSON` to Downloadable (VideoMediaItem)\n return {\n type: 'video',\n id: mediaId,\n filename: vidInc?.filename || null,\n mimeType: vidInc?.mimeType || null,\n createdAt: vidInc?.createdAt || null,\n size: {\n width: attrJSON.width || vidInc?.size.width,\n height: attrJSON.height || vidInc?.size.height\n },\n duration: attrJSON.duration || vidInc?.duration,\n downloadURL: downloadURL || vidInc?.downloadURL,\n displayURLs: {\n thumbnail: vidInc?.displayURLs.thumbnail || null,\n video: displayURL || vidInc?.downloadURL\n }\n };\n };\n\n // Video preview\n let videoPreview: Downloadable | null = null;\n const vidPreviewJSON = attributes.video_preview;\n if (vidPreviewJSON && typeof vidPreviewJSON === 'object') {\n videoPreview = __getVideoMediaItemFromAttr(vidPreviewJSON);\n if (!videoPreview.downloadURL && !videoPreview.displayURLs.video) {\n this.log('warn', `Video preview for post #${id} is missing URLs`);\n }\n }\n\n // Video - `postType` is 'video_external_file' and has `postFile`\n let video: Downloadable | null = null;\n const postFileJSON = attributes.post_file;\n const hasPostFile = postFileJSON && typeof postFileJSON === 'object';\n if (attributes.post_type === 'video_external_file' && hasPostFile) {\n video = __getVideoMediaItemFromAttr(postFileJSON);\n if (!video.downloadURL && !video.displayURLs.video) {\n this.log('warn', `Video for post #${id} is missing URLs`);\n }\n }\n\n // Cover image\n let coverImage: PostCoverImageMediaItem | null = null;\n if (attributes.image) {\n coverImage = {\n type: 'image',\n id,\n filename: isViewable ? 'cover-image' : 'cover-image-preview',\n mimeType: null,\n imageType: 'postCoverImage',\n imageURLs: {\n large: ObjectHelper.getProperty(attributes, 'image.large_url') || null,\n thumbSquareLarge: ObjectHelper.getProperty(attributes, 'image.thumb_square_large_url') || null,\n thumbSquare: ObjectHelper.getProperty(attributes, 'image.thumb_square_url') || null,\n thumb: ObjectHelper.getProperty(attributes, 'image.thumb_url') || null,\n default: ObjectHelper.getProperty(attributes, 'image.url') || null\n }\n };\n }\n\n // Thumbnail\n let thumbnail: PostThumbnailMediaItem | null = null;\n if (attributes.thumbnail) {\n thumbnail = {\n type: 'image',\n id,\n filename: isViewable ? 'thumbnail' : 'thumbnail-preview',\n mimeType: null,\n imageType: 'postThumbnail',\n imageURLs: {\n large: ObjectHelper.getProperty(attributes, 'thumbnail.large') || null,\n large2: ObjectHelper.getProperty(attributes, 'thumbnail.large_2') || null,\n square: ObjectHelper.getProperty(attributes, 'thumbnail.square') || null,\n default: ObjectHelper.getProperty(attributes, 'thumbnail.url') || null\n }\n };\n }\n\n // Embed\n const embedJSON = attributes.embed;\n let embed: PostEmbed | null = null;\n if (embedJSON && typeof embedJSON === 'object') {\n let embedType: PostEmbed['type'];\n switch (attributes.post_type) {\n case 'video_embed':\n embedType = 'video';\n break;\n case 'link':\n embedType = 'link';\n break;\n default:\n embedType = 'unknown';\n }\n embed = {\n type: embedType,\n description: embedJSON.descripton || null,\n html: embedJSON.html || null,\n provider: embedJSON.provider || null,\n providerURL: embedJSON.provider_url || null,\n subject: embedJSON.subject || null,\n url: embedJSON.url || null\n };\n }\n\n const post: Post = {\n id,\n type: 'post',\n postType: attributes.post_type || null,\n isViewable,\n url: attributes.url || null,\n title: attributes.title || null,\n content: attributes.content || null,\n teaserText: attributes.teaser_text || null,\n publishedAt: attributes.published_at || null,\n editedAt: attributes.edited_at || null,\n coverImage,\n thumbnail,\n embed,\n attachments,\n audio,\n audioPreview,\n images,\n videoPreview,\n video,\n campaign: null,\n raw: json\n };\n\n this.log('debug', `Done parsing post #${id}`);\n\n collection.posts.push(post);\n }\n\n if (campaign) {\n this.log('debug', `Campaign #${campaign.id} found while parsing posts`);\n for (const post of collection.posts) {\n post.campaign = campaign;\n }\n }\n else {\n this.log('warn', 'No campaign info found while parsing posts');\n }\n\n this.log('debug', 'Done parsing posts');\n\n return collection;\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { Product } from '../entities/Product.js';
2
+ import Parser from './Parser.js';
3
+ export default class ProductParser extends Parser {
4
+ protected name: string;
5
+ parseProductAPIResponse(json: any, _url: string, _id: string): Product;
6
+ }
7
+ //# sourceMappingURL=ProductParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductParser.d.ts","sourceRoot":"","sources":["../../src/parsers/ProductParser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,MAAM;IAE/C,SAAS,CAAC,IAAI,SAAmB;IAEjC,uBAAuB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CAgFvE"}
@@ -0,0 +1,70 @@
1
+ import ObjectHelper from '../utils/ObjectHelper.js';
2
+ import Parser from './Parser.js';
3
+ export default class ProductParser extends Parser {
4
+ constructor() {
5
+ super(...arguments);
6
+ this.name = 'ProductParser';
7
+ }
8
+ parseProductAPIResponse(json, _url, _id) {
9
+ const campaignId = ObjectHelper.getProperty(json, 'data.relationships.campaign.data.id') || null;
10
+ const includedJSON = json.included;
11
+ this.log('debug', `Parse API response for product #${_id}`);
12
+ let hasIncludedJSON = true;
13
+ if (!includedJSON || !Array.isArray(includedJSON)) {
14
+ this.log('warn', `'included' field missing in API data of product #${_id} or has incorrect type - no media items and campaign info will be returned`);
15
+ hasIncludedJSON = false;
16
+ }
17
+ let campaign = null;
18
+ if (!campaignId || typeof campaignId !== 'string') {
19
+ this.log('warn', `Campaign ID missing in API data of product #${_id} or has incorrect type - no campaign info will be available`);
20
+ }
21
+ else if (hasIncludedJSON) {
22
+ campaign = this.findInAPIResponseIncludedArray(includedJSON, campaignId, 'campaign');
23
+ }
24
+ let previewMedia;
25
+ let contentMedia;
26
+ if (hasIncludedJSON) {
27
+ const relationships = ObjectHelper.getProperty(json, 'data.relationships') || {};
28
+ const downloadables = this.fetchDownloadablesFromRelationships(relationships, {
29
+ 'preview_media': 'preview media',
30
+ 'content_media': 'content media'
31
+ }, includedJSON, `product #${_id}`);
32
+ previewMedia = downloadables['preview_media'] || [];
33
+ contentMedia = downloadables['content_media'] || [];
34
+ }
35
+ else {
36
+ previewMedia = [];
37
+ contentMedia = [];
38
+ }
39
+ const id = ObjectHelper.getProperty(json, 'data.id') || _id;
40
+ const attributes = ObjectHelper.getProperty(json, 'data.attributes') || {};
41
+ const { name = null, description = null, published_at_datetime: publishedAt = null, url = _url } = attributes;
42
+ // Is accessible?
43
+ let isAccessible = false;
44
+ const accessMetadata = attributes.access_metadata;
45
+ if (accessMetadata && Array.isArray(accessMetadata)) {
46
+ isAccessible = accessMetadata.some((acc) => acc.access_created_at);
47
+ }
48
+ let price = null;
49
+ if (attributes.price_cents !== undefined && !isNaN(Number(attributes.price_cents))) {
50
+ const currency = campaign?.currency ? ` ${campaign?.currency}` : '';
51
+ price = `${Number(attributes.price_cents) / 100}${currency}`;
52
+ }
53
+ this.log('debug', `Done parsing product #${id}`);
54
+ return {
55
+ id,
56
+ type: 'product',
57
+ isAccessible,
58
+ name,
59
+ description,
60
+ price,
61
+ publishedAt,
62
+ url,
63
+ campaign,
64
+ previewMedia,
65
+ contentMedia,
66
+ raw: json
67
+ };
68
+ }
69
+ }
70
+ //# sourceMappingURL=ProductParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductParser.js","sourceRoot":"","sources":["../../src/parsers/ProductParser.ts"],"names":[],"mappings":"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","sourcesContent":["import { Campaign } from '../entities/Campaign.js';\nimport { Downloadable } from '../entities/Downloadable.js';\nimport { Product } from '../entities/Product.js';\nimport ObjectHelper from '../utils/ObjectHelper.js';\nimport Parser from './Parser.js';\n\nexport default class ProductParser extends Parser {\n\n protected name = 'ProductParser';\n\n parseProductAPIResponse(json: any, _url: string, _id: string): Product {\n const campaignId = ObjectHelper.getProperty(json, 'data.relationships.campaign.data.id') || null;\n const includedJSON = json.included;\n\n this.log('debug', `Parse API response for product #${_id}`);\n\n let hasIncludedJSON = true;\n if (!includedJSON || !Array.isArray(includedJSON)) {\n this.log('warn', `'included' field missing in API data of product #${_id} or has incorrect type - no media items and campaign info will be returned`);\n hasIncludedJSON = false;\n }\n\n let campaign: Campaign | null = null;\n if (!campaignId || typeof campaignId !== 'string') {\n this.log('warn', `Campaign ID missing in API data of product #${_id} or has incorrect type - no campaign info will be available`);\n }\n else if (hasIncludedJSON) {\n campaign = this.findInAPIResponseIncludedArray(includedJSON, campaignId, 'campaign');\n }\n\n let previewMedia: Downloadable[];\n let contentMedia: Downloadable[];\n if (hasIncludedJSON) {\n const relationships = ObjectHelper.getProperty(json, 'data.relationships') || {};\n const downloadables = this.fetchDownloadablesFromRelationships(\n relationships,\n {\n 'preview_media': 'preview media',\n 'content_media': 'content media'\n },\n includedJSON,\n `product #${_id}`\n );\n previewMedia = downloadables['preview_media'] || [];\n contentMedia = downloadables['content_media'] || [];\n }\n else {\n previewMedia = [];\n contentMedia = [];\n }\n\n const id = ObjectHelper.getProperty(json, 'data.id') || _id;\n const attributes = ObjectHelper.getProperty(json, 'data.attributes') || {};\n const {\n name = null,\n description = null,\n published_at_datetime: publishedAt = null,\n url = _url\n } = attributes;\n\n // Is accessible?\n let isAccessible = false;\n const accessMetadata = attributes.access_metadata;\n if (accessMetadata && Array.isArray(accessMetadata)) {\n isAccessible = accessMetadata.some((acc) => acc.access_created_at);\n }\n\n let price: string | null = null;\n if (attributes.price_cents !== undefined && !isNaN(Number(attributes.price_cents))) {\n const currency = campaign?.currency ? ` ${campaign?.currency}` : '';\n price = `${Number(attributes.price_cents) / 100}${currency}`;\n }\n\n this.log('debug', `Done parsing product #${id}`);\n\n return {\n id,\n type: 'product',\n isAccessible,\n name,\n description,\n price,\n publishedAt,\n url,\n campaign,\n previewMedia,\n contentMedia,\n raw: json\n };\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import { Response } from 'node-fetch';
2
+ import FilenameResolver from './FllenameResolver.js';
3
+ import { Attachment } from '../entities/Attachment.js';
4
+ export default class AttachmentFilenameResolver<T extends Attachment> extends FilenameResolver<T> {
5
+ #private;
6
+ constructor(target: T, srcURL: string, format: string);
7
+ resolve(response: Response): string;
8
+ }
9
+ //# sourceMappingURL=AttachmentFilenameResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentFilenameResolver.d.ts","sourceRoot":"","sources":["../../src/utils/AttachmentFilenameResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,0BAA0B,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;;gBAInF,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAKrD,OAAO,CAAC,QAAQ,EAAE,QAAQ;CAuD3B"}
@@ -0,0 +1,73 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ 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");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _AttachmentFilenameResolver_format;
13
+ import path from 'path';
14
+ import FilenameResolver from './FllenameResolver.js';
15
+ import FilenameFormatHelper from './FilenameFormatHelper.js';
16
+ export default class AttachmentFilenameResolver extends FilenameResolver {
17
+ constructor(target, srcURL, format) {
18
+ super(target, srcURL);
19
+ _AttachmentFilenameResolver_format.set(this, void 0);
20
+ __classPrivateFieldSet(this, _AttachmentFilenameResolver_format, format, "f");
21
+ }
22
+ resolve(response) {
23
+ const att = this.target;
24
+ // Treat attachment name as filename
25
+ const attNameParts = att.name ? path.parse(att.name) : null;
26
+ const resFilenameParts = this.getFilenamePartsFromResponse(response);
27
+ const filenameParts = {
28
+ name: '',
29
+ ext: ''
30
+ };
31
+ /**
32
+ * Obtain `name` part from (in order of priority):
33
+ * 1. Filename from response headers
34
+ * 2. Attachment name
35
+ * 3. If none of the above is available, fallback to using the media ID
36
+ */
37
+ if (resFilenameParts.name) {
38
+ filenameParts.name = resFilenameParts.name;
39
+ }
40
+ if (attNameParts?.name) {
41
+ filenameParts.name = attNameParts.name;
42
+ }
43
+ else if (!__classPrivateFieldGet(this, _AttachmentFilenameResolver_format, "f").includes('{media.id}')) {
44
+ filenameParts.name = att.id;
45
+ }
46
+ /**
47
+ * Obtain `extension` from (in order of priority):
48
+ * 1. Response headers
49
+ * 2. Attachment name
50
+ *
51
+ * Unlike MediaFilenameResolver, do not get ext from srcURL.
52
+ * Download URLs for attachments have no extension
53
+ * (e.g. https://www.patreon.com/file?h=...)
54
+ */
55
+ if (resFilenameParts.ext) {
56
+ filenameParts.ext = resFilenameParts.ext;
57
+ }
58
+ else if (attNameParts?.ext) {
59
+ filenameParts.ext = attNameParts.ext;
60
+ }
61
+ const tmpAtt = {
62
+ ...att,
63
+ name: filenameParts.name
64
+ };
65
+ let resolvedFilename = FilenameFormatHelper.getAttachmentFilename(tmpAtt, __classPrivateFieldGet(this, _AttachmentFilenameResolver_format, "f"));
66
+ if (filenameParts.ext) {
67
+ resolvedFilename += filenameParts.ext;
68
+ }
69
+ return resolvedFilename;
70
+ }
71
+ }
72
+ _AttachmentFilenameResolver_format = new WeakMap();
73
+ //# sourceMappingURL=AttachmentFilenameResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentFilenameResolver.js","sourceRoot":"","sources":["../../src/utils/AttachmentFilenameResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AACrD,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAG7D,MAAM,CAAC,OAAO,OAAO,0BAAiD,SAAQ,gBAAmB;IAI/F,YAAY,MAAS,EAAE,MAAc,EAAE,MAAc;QACnD,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAHxB,qDAAgB;QAId,uBAAA,IAAI,sCAAW,MAAM,MAAA,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,QAAkB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,oCAAoC;QACpC,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,MAAM,gBAAgB,GAAG,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC;QAErE,MAAM,aAAa,GAAG;YACpB,IAAI,EAAE,EAAE;YACR,GAAG,EAAE,EAAE;SACR,CAAC;QAEF;;;;;UAKE;QACF,IAAI,gBAAgB,CAAC,IAAI,EAAE;YACzB,aAAa,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;SAC5C;QACD,IAAI,YAAY,EAAE,IAAI,EAAE;YACtB,aAAa,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;SACxC;aACI,IAAI,CAAC,uBAAA,IAAI,0CAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;YAC7C,aAAa,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;SAC7B;QAED;;;;;;;;WAQG;QACH,IAAI,gBAAgB,CAAC,GAAG,EAAE;YACxB,aAAa,CAAC,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC;SAC1C;aACI,IAAI,YAAY,EAAE,GAAG,EAAE;YAC1B,aAAa,CAAC,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC;SACtC;QAED,MAAM,MAAM,GAAG;YACb,GAAG,GAAG;YACN,IAAI,EAAE,aAAa,CAAC,IAAI;SACzB,CAAC;QAEF,IAAI,gBAAgB,GAAG,oBAAoB,CAAC,qBAAqB,CAAC,MAAM,EAAE,uBAAA,IAAI,0CAAQ,CAAC,CAAC;QACxF,IAAI,aAAa,CAAC,GAAG,EAAE;YACrB,gBAAgB,IAAI,aAAa,CAAC,GAAG,CAAC;SACvC;QAED,OAAO,gBAAgB,CAAC;IAC1B,CAAC;CACF","sourcesContent":["import path from 'path';\nimport { Response } from 'node-fetch';\nimport FilenameResolver from './FllenameResolver.js';\nimport FilenameFormatHelper from './FilenameFormatHelper.js';\nimport { Attachment } from '../entities/Attachment.js';\n\nexport default class AttachmentFilenameResolver<T extends Attachment> extends FilenameResolver<T> {\n\n #format: string;\n\n constructor(target: T, srcURL: string, format: string) {\n super(target, srcURL);\n this.#format = format;\n }\n\n resolve(response: Response) {\n const att = this.target;\n // Treat attachment name as filename\n const attNameParts = att.name ? path.parse(att.name) : null;\n const resFilenameParts = this.getFilenamePartsFromResponse(response);\n\n const filenameParts = {\n name: '',\n ext: ''\n };\n\n /**\n * Obtain `name` part from (in order of priority):\n * 1. Filename from response headers\n * 2. Attachment name\n * 3. If none of the above is available, fallback to using the media ID\n */\n if (resFilenameParts.name) {\n filenameParts.name = resFilenameParts.name;\n }\n if (attNameParts?.name) {\n filenameParts.name = attNameParts.name;\n }\n else if (!this.#format.includes('{media.id}')) {\n filenameParts.name = att.id;\n }\n\n /**\n * Obtain `extension` from (in order of priority):\n * 1. Response headers\n * 2. Attachment name\n *\n * Unlike MediaFilenameResolver, do not get ext from srcURL.\n * Download URLs for attachments have no extension\n * (e.g. https://www.patreon.com/file?h=...)\n */\n if (resFilenameParts.ext) {\n filenameParts.ext = resFilenameParts.ext;\n }\n else if (attNameParts?.ext) {\n filenameParts.ext = attNameParts.ext;\n }\n\n const tmpAtt = {\n ...att,\n name: filenameParts.name\n };\n\n let resolvedFilename = FilenameFormatHelper.getAttachmentFilename(tmpAtt, this.#format);\n if (filenameParts.ext) {\n resolvedFilename += filenameParts.ext;\n }\n\n return resolvedFilename;\n }\n}\n"]}
@@ -0,0 +1,57 @@
1
+ import { Product } from '../entities/Product.js';
2
+ import { Campaign } from '../entities/Campaign.js';
3
+ import { DownloaderConfig } from '../downloaders/Downloader.js';
4
+ import { Post } from '../entities/Post.js';
5
+ import { FileExistsAction } from '../downloaders/DownloaderOptions.js';
6
+ export type WriteTextFileResult = {
7
+ status: 'completed';
8
+ filePath: string;
9
+ } | {
10
+ status: 'skipped';
11
+ message: string;
12
+ } | {
13
+ status: 'error';
14
+ filePath: string;
15
+ error: any;
16
+ };
17
+ export default class FSHelper {
18
+ static getCampaignDirs(campaign: Campaign, config: DownloaderConfig<any>): {
19
+ root: string;
20
+ info: string;
21
+ };
22
+ static getPostDirs(post: Post, config: DownloaderConfig<'post'>): {
23
+ root: string;
24
+ info: string;
25
+ audio: string;
26
+ video: string;
27
+ images: string;
28
+ audioPreview: string;
29
+ videoPreview: string;
30
+ imagePreviews: string;
31
+ attachments: string;
32
+ embed: string;
33
+ statusCache: string;
34
+ };
35
+ static getProductDirs(product: Product, config: DownloaderConfig<'product'>): {
36
+ root: string;
37
+ info: string;
38
+ contentMedia: string;
39
+ previewMedia: string;
40
+ statusCache: string;
41
+ };
42
+ static createDir(dir: string, parents?: boolean): string;
43
+ static checkFileExistsAndIncrement(file: string): {
44
+ filename: string;
45
+ filePath: string;
46
+ preceding: null;
47
+ } | {
48
+ filename: string;
49
+ filePath: string;
50
+ preceding: string;
51
+ };
52
+ static sanitizeFilePath(filePath: string): string;
53
+ static compareFiles(f1: string, f2: string): Promise<boolean>;
54
+ static writeTextFile(file: string, data: string | object, fileExistsAction: FileExistsAction): Promise<WriteTextFileResult>;
55
+ static changeFilePathExtension(filePath: string, extension: `.${string}`): string;
56
+ }
57
+ //# sourceMappingURL=FSHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FSHelper.d.ts","sourceRoot":"","sources":["../../src/utils/FSHelper.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AA4BvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG;IACF,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG;IACF,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,GAAG,CAAA;CACX,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,QAAQ;IAE3B,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC;;;;IASxE,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;;;;;;;;;;;;;IA6B/D,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC;;;;;;;IAuB3E,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,UAAO;IAgB5C,MAAM,CAAC,2BAA2B,CAAC,IAAI,EAAE,MAAM;;;;;;;;;IAsC/C,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM;WAU3B,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;WAQnC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAuDjI,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,MAAM,EAAE;CAQzE"}