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,439 @@
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 _Parser_logger;
13
+ import capitalize from 'capitalize';
14
+ import { isTypeDownloadable } from '../entities/Downloadable.js';
15
+ import { commonLog } from '../utils/logging/Logger.js';
16
+ import ObjectHelper from '../utils/ObjectHelper.js';
17
+ export default class Parser {
18
+ constructor(logger) {
19
+ _Parser_logger.set(this, void 0);
20
+ __classPrivateFieldSet(this, _Parser_logger, logger, "f");
21
+ }
22
+ /**
23
+ *
24
+ * @param relationships `data[index].relationships`, where `data[index]` corresponds
25
+ * to a product or post returned in an API response.
26
+ * @param targets Fields in `relationships` to process, e.g. `audio`, `images`
27
+ * @param included The `included` array of API response
28
+ * @param parentName The name of the parent item containing `relationships`; for logging purpose.
29
+ * @returns
30
+ */
31
+ fetchDownloadablesFromRelationships(relationships, targets, included, parentName, warnOnTargetNotFound = true) {
32
+ const result = {};
33
+ for (const [target, targetName] of Object.entries(targets)) {
34
+ this.log('debug', `Fetch downloadable ${targetName} from ${parentName} ('relationships.${target}')`);
35
+ const rel = relationships[target];
36
+ /**
37
+ * A relationship is an object that takes one of two forms.
38
+ * E.g. for 'images':
39
+ * { "data": [ { "id": "12345", "type": "media" } ...] }
40
+ *
41
+ * For 'audio':
42
+ *
43
+ * { "data": { "id": "246113102", "type": "media" } }
44
+ *
45
+ * So `rel` must consist of `data`, which can be an object or an array of objects,
46
+ * with each object having `id` and `type`.
47
+ */
48
+ const relData = rel && typeof rel === 'object' ? rel.data : null;
49
+ let rData = null; // Normalized data
50
+ if (relData) {
51
+ if (Array.isArray(relData)) {
52
+ if (relData.every((r) => typeof r === 'object' && r.id && r.type)) {
53
+ rData = relData;
54
+ }
55
+ }
56
+ else if (typeof relData === 'object') {
57
+ if (relData.id && relData.type) {
58
+ rData = [relData];
59
+ }
60
+ }
61
+ }
62
+ if (!rData || rData.length === 0) {
63
+ if (warnOnTargetNotFound) {
64
+ this.log('warn', `${capitalize(targetName)} not found in API data of ${parentName} ('relationships.${target}')`);
65
+ }
66
+ continue;
67
+ }
68
+ this.log('debug', `Parse ${targetName}`);
69
+ const fetched = [];
70
+ let total = 0;
71
+ let found = 0;
72
+ for (const m of rData) {
73
+ const { id, type } = m;
74
+ if (id && type && isTypeDownloadable(type)) {
75
+ total++;
76
+ let mi;
77
+ if (type === 'media') {
78
+ const unknownMediaTypeAs = target === 'audio' ? 'audio' :
79
+ target === 'audio_preview' ? 'audio' :
80
+ target === 'images' ? 'image' :
81
+ undefined;
82
+ mi = this.findInAPIResponseIncludedArray(included, id, type, unknownMediaTypeAs);
83
+ }
84
+ else {
85
+ mi = this.findInAPIResponseIncludedArray(included, id, type);
86
+ }
87
+ if (mi) {
88
+ found++;
89
+ fetched.push(mi);
90
+ }
91
+ }
92
+ else {
93
+ this.log('debug', `Skipped non-downloadable item #${id} (type: ${type})`);
94
+ }
95
+ }
96
+ if (total === found) {
97
+ this.log('debug', `All ${total} downloadable ${targetName} parsed`);
98
+ }
99
+ else {
100
+ this.log('warn', `${found} / ${total} downloadable ${targetName} parsed for ${parentName}`);
101
+ }
102
+ result[target] = fetched;
103
+ }
104
+ return result;
105
+ }
106
+ findInAPIResponseIncludedArray(included, id, matchType, ...args) {
107
+ this.log('debug', `Find ${matchType} item #${id} in API response`);
108
+ for (const inc of included) {
109
+ if (inc && typeof inc === 'object' && inc.id === id && inc.type === matchType) {
110
+ this.log('debug', 'Found - parse item data');
111
+ if (matchType === 'media') {
112
+ return this.parseMediaItemAPIDataInIncludedArray(inc, args[0]);
113
+ }
114
+ else if (matchType === 'campaign') {
115
+ return this.parseCampaignAPIDataInIncludedArray(inc, included);
116
+ }
117
+ else if (matchType === 'user') {
118
+ return this.parseUserAPIDataInIncludedArray(inc, args[0]);
119
+ }
120
+ else if (matchType === 'reward') {
121
+ return this.parseRewardAPIDataInIncludedArray(inc);
122
+ }
123
+ else if (matchType === 'attachment') {
124
+ return this.parseAttachmentAPIDataInIncludedArray(inc);
125
+ }
126
+ }
127
+ }
128
+ this.log('warn', `Item #${id} not found in API response or has invalid data`);
129
+ return null;
130
+ }
131
+ parseMediaItemAPIDataInIncludedArray(data, unknownMediaTypeAs) {
132
+ const { id, attributes } = data;
133
+ if (!id) {
134
+ this.log('error', 'Parse error: \'id\' field missing in API data of media item');
135
+ return null;
136
+ }
137
+ if (!attributes || typeof attributes !== 'object') {
138
+ this.log('error', `Parse error: 'attributes' field missing in API data of media item #${id} or has incorrect type`);
139
+ return null;
140
+ }
141
+ const { file_name: filename = null, mimetype: mimeType = null, media_type: mediaType = null, created_at: createdAt = null } = attributes;
142
+ let mi = null;
143
+ if (mimeType === 'application/x-mpegURL' || mimeType?.startsWith('video/') || mediaType === 'video' || unknownMediaTypeAs === 'video') {
144
+ mi = {
145
+ type: 'video',
146
+ id,
147
+ filename,
148
+ createdAt,
149
+ mimeType,
150
+ size: {
151
+ width: ObjectHelper.getProperty(attributes, 'display.width') || null,
152
+ height: ObjectHelper.getProperty(attributes, 'display.height') || null
153
+ },
154
+ duration: ObjectHelper.getProperty(attributes, 'display.duration') || null,
155
+ /**
156
+ * `attributes.download_url` in `included` array returns 404. Need to use `display.url`.
157
+ * For posts, actual download URL for accessible videos is encapsulated in `data.attributes.post_file`.
158
+ * That part is handled by `PostParser`.
159
+ */
160
+ // DownloadURL: attributes.download_url || null,
161
+ downloadURL: null,
162
+ displayURLs: {
163
+ thumbnail: ObjectHelper.getProperty(attributes, 'display.default_thumbnail.url') || null,
164
+ video: ObjectHelper.getProperty(attributes, 'display.url') || null
165
+ }
166
+ };
167
+ }
168
+ else if (mimeType?.startsWith('image/') || mediaType === 'image' || unknownMediaTypeAs === 'image') {
169
+ mi = {
170
+ type: 'image',
171
+ imageType: 'default',
172
+ id,
173
+ filename,
174
+ createdAt,
175
+ mimeType,
176
+ downloadURL: attributes.download_url || null,
177
+ imageURLs: {
178
+ default: ObjectHelper.getProperty(attributes, 'image_urls.default') || null,
179
+ defaultSmall: ObjectHelper.getProperty(attributes, 'image_urls.default_small') || null,
180
+ original: ObjectHelper.getProperty(attributes, 'image_urls.original') || null,
181
+ thumbnail: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail') || null,
182
+ thumbnailLarge: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_large') || null,
183
+ thumbnailSmall: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_small') || null
184
+ }
185
+ };
186
+ }
187
+ else if (mimeType?.startsWith('audio/') || mediaType === 'audio' || unknownMediaTypeAs === 'audio') {
188
+ mi = {
189
+ type: 'audio',
190
+ id,
191
+ filename,
192
+ createdAt,
193
+ mimeType,
194
+ /**
195
+ * Audio item data in API response can have identical structure as image, i.e. with `image_urls.thumbnail`,
196
+ * `image_urls.original`, etc. These URLs all point to the same file, so it's only necessary to return
197
+ * a single URL.
198
+ */
199
+ url: ObjectHelper.getProperty(attributes, 'image_urls.original') ||
200
+ ObjectHelper.getProperty(attributes, 'image_urls.default') ||
201
+ attributes.download_url ||
202
+ ObjectHelper.getProperty(attributes, 'image_urls.default_small') ||
203
+ ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_large') ||
204
+ ObjectHelper.getProperty(attributes, 'image_urls.thumbnail') ||
205
+ ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_small') ||
206
+ null
207
+ };
208
+ }
209
+ else if (mediaType === 'file' || unknownMediaTypeAs === 'file') {
210
+ mi = {
211
+ type: 'file',
212
+ id,
213
+ filename,
214
+ createdAt,
215
+ mimeType,
216
+ downloadURL: attributes.download_url || null // TODO: test this
217
+ };
218
+ }
219
+ else {
220
+ this.log('warn', `Media item #${id} has unrecognized media type '${mediaType}' or mime type '${mimeType}'`);
221
+ }
222
+ if (mi) {
223
+ this.log('debug', `Done parsing media item #${id} (type: ${mi.type})`);
224
+ }
225
+ return mi;
226
+ }
227
+ parseCampaignAPIDataInIncludedArray(data, included) {
228
+ const { id, attributes } = data;
229
+ if (!id) {
230
+ this.log('error', 'Parse error: \'id\' field missing in API data of campaign');
231
+ return null;
232
+ }
233
+ if (!attributes || typeof attributes !== 'object') {
234
+ this.log('error', `Parse error: 'attributes' field missing in API data of campaign #${id} or has incorrect type`);
235
+ return null;
236
+ }
237
+ const rewards = [];
238
+ const rewardsData = ObjectHelper.getProperty(data, 'relationships.rewards.data');
239
+ if (rewardsData && Array.isArray(rewardsData)) {
240
+ let invalidRewardDataCount = 0;
241
+ for (const rewardData of rewardsData) {
242
+ if (typeof rewardData === 'object') {
243
+ const { id: rewardId, type } = rewardData;
244
+ if (type !== 'reward') {
245
+ continue;
246
+ }
247
+ if (rewardId === undefined) {
248
+ invalidRewardDataCount++;
249
+ continue;
250
+ }
251
+ const reward = this.findInAPIResponseIncludedArray(included, rewardId, 'reward');
252
+ if (reward) {
253
+ rewards.push(reward);
254
+ }
255
+ else {
256
+ invalidRewardDataCount++;
257
+ }
258
+ }
259
+ else {
260
+ invalidRewardDataCount++;
261
+ }
262
+ }
263
+ if (invalidRewardDataCount > 0) {
264
+ this.log('warn', `${invalidRewardDataCount} rewards for campaign #${id} could not be parsed due to invalid data`);
265
+ }
266
+ }
267
+ else {
268
+ this.log('warn', `Rewards data for campaign #${id} is missing or has incorrect type`);
269
+ }
270
+ const creatorId = ObjectHelper.getProperty(data, 'relationships.creator.data.id');
271
+ const creatorType = ObjectHelper.getProperty(data, 'relationships.creator.data.type');
272
+ let creator = null;
273
+ if (!creatorId) {
274
+ this.log('warn', `Creator ID missing in API data of campaign #${id} - no creator info will be available`);
275
+ }
276
+ else if (creatorType !== 'user') {
277
+ this.log('warn', `Creator of campaign #${id} has incorrect type (expecting 'user' but got '${creatorType}') - no creator info will be available`);
278
+ }
279
+ else {
280
+ this.log('debug', `Obtain creator info (user ID '${creatorId}')`);
281
+ creator = this.findInAPIResponseIncludedArray(included, creatorId, 'user', true);
282
+ }
283
+ const avatarImage = {
284
+ type: 'image',
285
+ id,
286
+ filename: 'avatar',
287
+ createdAt: null,
288
+ mimeType: null,
289
+ downloadURL: null,
290
+ imageType: 'default',
291
+ imageURLs: {
292
+ default: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.default') || null,
293
+ defaultSmall: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.default_small') || null,
294
+ original: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.original') || null,
295
+ thumbnail: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail') || null,
296
+ thumbnailLarge: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail_large') || null,
297
+ thumbnailSmall: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail_small') || null
298
+ }
299
+ };
300
+ const coverPhoto = {
301
+ type: 'image',
302
+ id,
303
+ filename: 'cover-photo',
304
+ mimeType: null,
305
+ imageType: 'campaignCoverPhoto',
306
+ imageURLs: {
307
+ large: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.large') || null,
308
+ medium: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.medium') || null,
309
+ small: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.small') || null,
310
+ xlarge: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.xlarge') || null,
311
+ xsmall: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.xsmall') || null
312
+ }
313
+ };
314
+ const campaign = {
315
+ type: 'campaign',
316
+ id,
317
+ name: attributes.name,
318
+ createdAt: attributes.created_at || null,
319
+ publishedAt: attributes.published_at || null,
320
+ avatarImage,
321
+ coverPhoto,
322
+ summary: attributes.summary,
323
+ url: attributes.url || null,
324
+ currency: attributes.currency || null,
325
+ rewards,
326
+ creator,
327
+ raw: data
328
+ };
329
+ this.log('debug', `Done parsing campaign #${id}`);
330
+ return campaign;
331
+ }
332
+ parseUserAPIDataInIncludedArray(data, asCreator = false) {
333
+ const { id, attributes } = data;
334
+ if (!id) {
335
+ this.log('error', 'Parse error: \'id\' field missing in API data of user');
336
+ return null;
337
+ }
338
+ if (!attributes || typeof attributes !== 'object') {
339
+ this.log('error', `Parse error: 'attributes' field missing in API data of user #${id} or has incorrect type`);
340
+ return null;
341
+ }
342
+ const image = {
343
+ type: 'image',
344
+ id,
345
+ filename: asCreator ? 'creator-image' : 'user-image',
346
+ mimeType: null,
347
+ imageType: 'single',
348
+ imageURL: attributes.image_url || null
349
+ };
350
+ const thumbnail = {
351
+ type: 'image',
352
+ id,
353
+ filename: asCreator ? 'creator-thumbnail' : 'user-thumbnail',
354
+ mimeType: null,
355
+ imageType: 'single',
356
+ imageURL: attributes.thumb_url || null
357
+ };
358
+ const user = {
359
+ type: 'user',
360
+ id,
361
+ firstName: attributes.first_name,
362
+ lastName: attributes.last_name,
363
+ fullName: attributes.full_name,
364
+ createdAt: attributes.created || null,
365
+ image,
366
+ thumbnail,
367
+ url: attributes.url,
368
+ vanity: attributes.vanity,
369
+ raw: data
370
+ };
371
+ this.log('debug', `Done parsing user #${id}`);
372
+ return user;
373
+ }
374
+ parseRewardAPIDataInIncludedArray(data) {
375
+ const { id, attributes } = data;
376
+ if (!id) {
377
+ this.log('error', 'Parse error: \'id\' field missing in API data of reward');
378
+ return null;
379
+ }
380
+ if (!attributes || typeof attributes !== 'object') {
381
+ this.log('error', `Parse error: 'attributes' field missing in API data of reward #${id} or has incorrect type`);
382
+ return null;
383
+ }
384
+ const amountCents = attributes.amount_cents !== undefined ? attributes.amount_cents : null;
385
+ const amountCurrency = attributes.currency || null;
386
+ let amount = null;
387
+ if (amountCents !== null && !isNaN(Number(amountCents)) && amountCurrency !== null) {
388
+ amount = `${Number(amountCents) / 100} ${amountCurrency}`;
389
+ }
390
+ const title = attributes.title || null;
391
+ const rewardFilenameSuffix = title ? ` (${title})` : `-${id}`;
392
+ const image = attributes.image_url ? {
393
+ type: 'image',
394
+ id,
395
+ filename: `reward${rewardFilenameSuffix}`,
396
+ mimeType: null,
397
+ imageType: 'single',
398
+ imageURL: attributes.image_url
399
+ } : null;
400
+ const reward = {
401
+ type: 'reward',
402
+ id,
403
+ title,
404
+ description: attributes.description || null,
405
+ amount,
406
+ createdAt: attributes.created_at || null,
407
+ publishedAt: attributes.published_at || null,
408
+ editedAt: attributes.edited_at || null,
409
+ image,
410
+ url: attributes.url || null
411
+ };
412
+ this.log('debug', `Done parsing reward #${id}`);
413
+ return reward;
414
+ }
415
+ parseAttachmentAPIDataInIncludedArray(data) {
416
+ const { id, attributes } = data;
417
+ if (!id) {
418
+ this.log('error', 'Parse error: \'id\' field missing in API data of attachment');
419
+ return null;
420
+ }
421
+ if (!attributes || typeof attributes !== 'object') {
422
+ this.log('error', `Parse error: 'attributes' field missing in API data of attachment #${id} or has incorrect type`);
423
+ return null;
424
+ }
425
+ const attachment = {
426
+ type: 'attachment',
427
+ id,
428
+ name: attributes.name || null,
429
+ url: attributes.url || null
430
+ };
431
+ this.log('debug', `Done parsing attachment #${id}`);
432
+ return attachment;
433
+ }
434
+ log(level, ...msg) {
435
+ commonLog(__classPrivateFieldGet(this, _Parser_logger, "f"), level, this.name, ...msg);
436
+ }
437
+ }
438
+ _Parser_logger = new WeakMap();
439
+ //# sourceMappingURL=Parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Parser.js","sourceRoot":"","sources":["../../src/parsers/Parser.ts"],"names":[],"mappings":"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","sourcesContent":["import capitalize from 'capitalize';\nimport { Campaign } from '../entities/Campaign.js';\nimport { DOWNLOADABLE_TYPES, Downloadable, isTypeDownloadable } from '../entities/Downloadable.js';\nimport { CampaignCoverPhotoMediaItem, DefaultImageMediaItem, MediaItem, SingleImageMediaItem } from '../entities/MediaItem.js';\nimport { User } from '../entities/User.js';\nimport Logger, { LogLevel, commonLog } from '../utils/logging/Logger.js';\nimport ObjectHelper from '../utils/ObjectHelper.js';\nimport { Attachment } from '../entities/Attachment.js';\nimport { Reward } from '../entities/Reward.js';\n\nexport default abstract class Parser {\n\n protected abstract name: string;\n\n #logger?: Logger | null;\n\n constructor(logger?: Logger | null) {\n this.#logger = logger;\n }\n\n /**\n *\n * @param relationships `data[index].relationships`, where `data[index]` corresponds\n * to a product or post returned in an API response.\n * @param targets Fields in `relationships` to process, e.g. `audio`, `images`\n * @param included The `included` array of API response\n * @param parentName The name of the parent item containing `relationships`; for logging purpose.\n * @returns\n */\n protected fetchDownloadablesFromRelationships<T extends Record<string, string>>(\n relationships: any,\n targets: T,\n included: any,\n parentName: string,\n warnOnTargetNotFound = true): Partial<Record<keyof T, Downloadable[]>> {\n\n const result: Partial<Record<keyof T, Downloadable[]>> = {};\n\n for (const [ target, targetName ] of Object.entries<string>(targets)) {\n this.log('debug', `Fetch downloadable ${targetName} from ${parentName} ('relationships.${target}')`);\n const rel = relationships[target];\n /**\n * A relationship is an object that takes one of two forms.\n * E.g. for 'images':\n * { \"data\": [ { \"id\": \"12345\", \"type\": \"media\" } ...] }\n *\n * For 'audio':\n *\n * { \"data\": { \"id\": \"246113102\", \"type\": \"media\" } }\n *\n * So `rel` must consist of `data`, which can be an object or an array of objects,\n * with each object having `id` and `type`.\n */\n const relData = rel && typeof rel === 'object' ? rel.data : null;\n let rData: { id: any; type: any }[] | null = null; // Normalized data\n if (relData) {\n if (Array.isArray(relData)) {\n if (relData.every((r) => typeof r === 'object' && r.id && r.type)) {\n rData = relData;\n }\n }\n else if (typeof relData === 'object') {\n if (relData.id && relData.type) {\n rData = [ relData ];\n }\n }\n }\n\n if (!rData || rData.length === 0) {\n if (warnOnTargetNotFound) {\n this.log('warn', `${capitalize(targetName)} not found in API data of ${parentName} ('relationships.${target}')`);\n }\n continue;\n }\n\n this.log('debug', `Parse ${targetName}`);\n const fetched: Downloadable[] = [];\n let total = 0;\n let found = 0;\n for (const m of rData) {\n const { id, type } = m;\n if (id && type && isTypeDownloadable(type)) {\n total++;\n let mi;\n if (type === 'media') {\n const unknownMediaTypeAs =\n target === 'audio' ? 'audio' :\n target === 'audio_preview' ? 'audio' :\n target === 'images' ? 'image' :\n undefined;\n mi = this.findInAPIResponseIncludedArray(included, id, type, unknownMediaTypeAs);\n }\n else {\n mi = this.findInAPIResponseIncludedArray(included, id, type);\n }\n if (mi) {\n found++;\n fetched.push(mi);\n }\n }\n else {\n this.log('debug', `Skipped non-downloadable item #${id} (type: ${type})`);\n }\n }\n if (total === found) {\n this.log('debug', `All ${total} downloadable ${targetName} parsed`);\n }\n else {\n this.log('warn', `${found} / ${total} downloadable ${targetName} parsed for ${parentName}`);\n }\n result[target as keyof T] = fetched;\n }\n\n return result;\n }\n\n /**\n * A JSON API response typically contain an `included` field, which is an array\n * of items (media, campaign, reward, etc.) that are referenced through its `id`\n * by items contained in the `data` field of the same response.\n *\n * Items in the `included` field contain extra info, such as media URLs,\n * not provided in the `data` items referencing it.\n */\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: typeof DOWNLOADABLE_TYPES[number]): Downloadable | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: 'media', unknownMediaTypeAs?: 'image' | 'video' | 'audio' | 'file'): MediaItem | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: 'reward'): Reward | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: 'user', asCreator?: boolean): User | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: 'campaign'): Campaign | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: 'attachment'): Attachment | null;\n protected findInAPIResponseIncludedArray(included: Array<any>, id: string, matchType: string, ...args: any[]): any {\n this.log('debug', `Find ${matchType} item #${id} in API response`);\n for (const inc of included) {\n if (inc && typeof inc === 'object' && inc.id === id && inc.type === matchType) {\n this.log('debug', 'Found - parse item data');\n\n if (matchType === 'media') {\n return this.parseMediaItemAPIDataInIncludedArray(inc, args[0]);\n }\n else if (matchType === 'campaign') {\n return this.parseCampaignAPIDataInIncludedArray(inc, included);\n }\n else if (matchType === 'user') {\n return this.parseUserAPIDataInIncludedArray(inc, args[0]);\n }\n else if (matchType === 'reward') {\n return this.parseRewardAPIDataInIncludedArray(inc);\n }\n else if (matchType === 'attachment') {\n return this.parseAttachmentAPIDataInIncludedArray(inc);\n }\n }\n }\n\n this.log('warn', `Item #${id} not found in API response or has invalid data`);\n return null;\n }\n\n protected parseMediaItemAPIDataInIncludedArray(data: any, unknownMediaTypeAs?: 'image' | 'video' | 'audio' | 'file') {\n const { id, attributes } = data;\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of media item');\n return null;\n }\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of media item #${id} or has incorrect type`);\n return null;\n }\n\n const {\n file_name: filename = null,\n mimetype: mimeType = null,\n media_type: mediaType = null,\n created_at: createdAt = null\n } = attributes;\n\n let mi: MediaItem | null = null;\n if (mimeType === 'application/x-mpegURL' || mimeType?.startsWith('video/') || mediaType === 'video' || unknownMediaTypeAs === 'video') {\n mi = {\n type: 'video',\n id,\n filename,\n createdAt,\n mimeType,\n size: {\n width: ObjectHelper.getProperty(attributes, 'display.width') || null,\n height: ObjectHelper.getProperty(attributes, 'display.height') || null\n },\n duration: ObjectHelper.getProperty(attributes, 'display.duration') || null,\n /**\n * `attributes.download_url` in `included` array returns 404. Need to use `display.url`.\n * For posts, actual download URL for accessible videos is encapsulated in `data.attributes.post_file`.\n * That part is handled by `PostParser`.\n */\n // DownloadURL: attributes.download_url || null,\n downloadURL: null,\n displayURLs: {\n thumbnail: ObjectHelper.getProperty(attributes, 'display.default_thumbnail.url') || null,\n video: ObjectHelper.getProperty(attributes, 'display.url') || null\n }\n };\n }\n else if (mimeType?.startsWith('image/') || mediaType === 'image' || unknownMediaTypeAs === 'image') {\n mi = {\n type: 'image',\n imageType: 'default',\n id,\n filename,\n createdAt,\n mimeType,\n downloadURL: attributes.download_url || null,\n imageURLs: {\n default: ObjectHelper.getProperty(attributes, 'image_urls.default') || null,\n defaultSmall: ObjectHelper.getProperty(attributes, 'image_urls.default_small') || null,\n original: ObjectHelper.getProperty(attributes, 'image_urls.original') || null,\n thumbnail: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail') || null,\n thumbnailLarge: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_large') || null,\n thumbnailSmall: ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_small') || null\n }\n };\n }\n else if (mimeType?.startsWith('audio/') || mediaType === 'audio' || unknownMediaTypeAs === 'audio') {\n mi = {\n type: 'audio',\n id,\n filename,\n createdAt,\n mimeType,\n /**\n * Audio item data in API response can have identical structure as image, i.e. with `image_urls.thumbnail`,\n * `image_urls.original`, etc. These URLs all point to the same file, so it's only necessary to return\n * a single URL.\n */\n url: ObjectHelper.getProperty(attributes, 'image_urls.original') ||\n ObjectHelper.getProperty(attributes, 'image_urls.default') ||\n attributes.download_url ||\n ObjectHelper.getProperty(attributes, 'image_urls.default_small') ||\n ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_large') ||\n ObjectHelper.getProperty(attributes, 'image_urls.thumbnail') ||\n ObjectHelper.getProperty(attributes, 'image_urls.thumbnail_small') ||\n null\n };\n }\n else if (mediaType === 'file' || unknownMediaTypeAs === 'file') {\n mi = {\n type: 'file',\n id,\n filename,\n createdAt,\n mimeType,\n downloadURL: attributes.download_url || null // TODO: test this\n };\n }\n else {\n this.log('warn', `Media item #${id} has unrecognized media type '${mediaType}' or mime type '${mimeType}'`);\n }\n\n if (mi) {\n this.log('debug', `Done parsing media item #${id} (type: ${mi.type})`);\n }\n\n return mi;\n }\n\n protected parseCampaignAPIDataInIncludedArray(data: any, included: Array<any>) {\n const { id, attributes } = data;\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of campaign');\n return null;\n }\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of campaign #${id} or has incorrect type`);\n return null;\n }\n\n const rewards: Reward[] = [];\n const rewardsData = ObjectHelper.getProperty(data, 'relationships.rewards.data');\n if (rewardsData && Array.isArray(rewardsData)) {\n let invalidRewardDataCount = 0;\n for (const rewardData of rewardsData) {\n if (typeof rewardData === 'object') {\n const { id: rewardId, type } = rewardData;\n if (type !== 'reward') {\n continue;\n }\n if (rewardId === undefined) {\n invalidRewardDataCount++;\n continue;\n }\n const reward = this.findInAPIResponseIncludedArray(included, rewardId, 'reward');\n if (reward) {\n rewards.push(reward);\n }\n else {\n invalidRewardDataCount++;\n }\n }\n else {\n invalidRewardDataCount++;\n }\n }\n if (invalidRewardDataCount > 0) {\n this.log('warn', `${invalidRewardDataCount} rewards for campaign #${id} could not be parsed due to invalid data`);\n }\n }\n else {\n this.log('warn', `Rewards data for campaign #${id} is missing or has incorrect type`);\n }\n\n const creatorId = ObjectHelper.getProperty(data, 'relationships.creator.data.id');\n const creatorType = ObjectHelper.getProperty(data, 'relationships.creator.data.type');\n let creator: User | null = null;\n if (!creatorId) {\n this.log('warn', `Creator ID missing in API data of campaign #${id} - no creator info will be available`);\n }\n else if (creatorType !== 'user') {\n this.log('warn', `Creator of campaign #${id} has incorrect type (expecting 'user' but got '${creatorType}') - no creator info will be available`);\n }\n else {\n this.log('debug', `Obtain creator info (user ID '${creatorId}')`);\n creator = this.findInAPIResponseIncludedArray(included, creatorId, 'user', true);\n }\n const avatarImage: DefaultImageMediaItem = {\n type: 'image',\n id, // Use campaign ID\n filename: 'avatar',\n createdAt: null,\n mimeType: null,\n downloadURL: null,\n imageType: 'default',\n imageURLs: {\n default: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.default') || null,\n defaultSmall: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.default_small') || null,\n original: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.original') || null,\n thumbnail: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail') || null,\n thumbnailLarge: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail_large') || null,\n thumbnailSmall: ObjectHelper.getProperty(attributes, 'avatar_photo_image_urls.thumbnail_small') || null\n }\n };\n const coverPhoto: CampaignCoverPhotoMediaItem = {\n type: 'image',\n id, // Use campaign ID\n filename: 'cover-photo',\n mimeType: null,\n imageType: 'campaignCoverPhoto',\n imageURLs: {\n large: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.large') || null,\n medium: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.medium') || null,\n small: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.small') || null,\n xlarge: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.xlarge') || null,\n xsmall: ObjectHelper.getProperty(attributes, 'cover_photo_url_sizes.xsmall') || null\n }\n };\n\n const campaign: Campaign = {\n type: 'campaign',\n id,\n name: attributes.name,\n createdAt: attributes.created_at || null,\n publishedAt: attributes.published_at || null,\n avatarImage,\n coverPhoto,\n summary: attributes.summary,\n url: attributes.url || null,\n currency: attributes.currency || null,\n rewards,\n creator,\n raw: data\n };\n this.log('debug', `Done parsing campaign #${id}`);\n return campaign;\n }\n\n protected parseUserAPIDataInIncludedArray(data: any, asCreator = false) {\n const { id, attributes } = data;\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of user');\n return null;\n }\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of user #${id} or has incorrect type`);\n return null;\n }\n const image: SingleImageMediaItem = {\n type: 'image',\n id,\n filename: asCreator ? 'creator-image' : 'user-image',\n mimeType: null,\n imageType: 'single',\n imageURL: attributes.image_url || null\n };\n const thumbnail: SingleImageMediaItem = {\n type: 'image',\n id,\n filename: asCreator ? 'creator-thumbnail' : 'user-thumbnail',\n mimeType: null,\n imageType: 'single',\n imageURL: attributes.thumb_url || null\n };\n const user: User = {\n type: 'user',\n id,\n firstName: attributes.first_name,\n lastName: attributes.last_name,\n fullName: attributes.full_name,\n createdAt: attributes.created || null,\n image,\n thumbnail,\n url: attributes.url,\n vanity: attributes.vanity,\n raw: data\n };\n this.log('debug', `Done parsing user #${id}`);\n return user;\n }\n\n protected parseRewardAPIDataInIncludedArray(data: any) {\n const { id, attributes } = data;\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of reward');\n return null;\n }\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of reward #${id} or has incorrect type`);\n return null;\n }\n const amountCents = attributes.amount_cents !== undefined ? attributes.amount_cents : null;\n const amountCurrency = attributes.currency || null;\n let amount: string | null = null;\n if (amountCents !== null && !isNaN(Number(amountCents)) && amountCurrency !== null) {\n amount = `${Number(amountCents) / 100} ${amountCurrency}`;\n }\n const title = attributes.title || null;\n const rewardFilenameSuffix = title ? ` (${title})` : `-${id}`;\n const image: SingleImageMediaItem | null = attributes.image_url ? {\n type: 'image',\n id,\n filename: `reward${rewardFilenameSuffix}`,\n mimeType: null,\n imageType: 'single',\n imageURL: attributes.image_url\n } : null;\n const reward: Reward = {\n type: 'reward',\n id,\n title,\n description: attributes.description || null,\n amount,\n createdAt: attributes.created_at || null,\n publishedAt: attributes.published_at || null,\n editedAt: attributes.edited_at || null,\n image,\n url: attributes.url || null\n };\n this.log('debug', `Done parsing reward #${id}`);\n return reward;\n }\n\n protected parseAttachmentAPIDataInIncludedArray(data: any) {\n const { id, attributes } = data;\n if (!id) {\n this.log('error', 'Parse error: \\'id\\' field missing in API data of attachment');\n return null;\n }\n if (!attributes || typeof attributes !== 'object') {\n this.log('error', `Parse error: 'attributes' field missing in API data of attachment #${id} or has incorrect type`);\n return null;\n }\n const attachment: Attachment = {\n type: 'attachment',\n id,\n name: attributes.name || null,\n url: attributes.url || null\n };\n this.log('debug', `Done parsing attachment #${id}`);\n return attachment;\n }\n\n protected log(level: LogLevel, ...msg: Array<any>) {\n commonLog(this.#logger, level, this.name, ...msg);\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { PostCollection } from '../entities/Post.js';
2
+ import Parser from './Parser.js';
3
+ export default class PostParser extends Parser {
4
+ protected name: string;
5
+ parsePostsAPIResponse(json: any, _url: string): PostCollection;
6
+ }
7
+ //# sourceMappingURL=PostParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostParser.d.ts","sourceRoot":"","sources":["../../src/parsers/PostParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAQ,cAAc,EAAa,MAAM,qBAAqB,CAAC;AAGtE,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,MAAM;IAE5C,SAAS,CAAC,IAAI,SAAgB;IAE9B,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc;CA4R/D"}