patreon-dl 3.4.0 → 3.5.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 (128) hide show
  1. package/README.md +15 -1
  2. package/dist/browse/api/CampaignAPIMixin.d.ts +1 -1
  3. package/dist/browse/api/ContentAPIMixin.d.ts +8 -2
  4. package/dist/browse/api/ContentAPIMixin.js +20 -0
  5. package/dist/browse/api/ContentAPIMixin.js.map +1 -1
  6. package/dist/browse/api/FilterAPIMixin.d.ts +1 -1
  7. package/dist/browse/api/FilterAPIMixin.js +29 -2
  8. package/dist/browse/api/FilterAPIMixin.js.map +1 -1
  9. package/dist/browse/api/index.d.ts +18 -6
  10. package/dist/browse/db/CampaignDBMixin.js +13 -1
  11. package/dist/browse/db/CampaignDBMixin.js.map +1 -1
  12. package/dist/browse/db/CollectionFTS.d.ts +2 -0
  13. package/dist/browse/db/CollectionFTS.js +68 -0
  14. package/dist/browse/db/CollectionFTS.js.map +1 -0
  15. package/dist/browse/db/ContentDBMixin.d.ts +14 -1
  16. package/dist/browse/db/ContentDBMixin.js +412 -15
  17. package/dist/browse/db/ContentDBMixin.js.map +1 -1
  18. package/dist/browse/db/Init.js +63 -5
  19. package/dist/browse/db/Init.js.map +1 -1
  20. package/dist/browse/db/MediaDBMixin.js +2 -6
  21. package/dist/browse/db/MediaDBMixin.js.map +1 -1
  22. package/dist/browse/db/PostFTS.d.ts +4 -0
  23. package/dist/browse/db/PostFTS.js +163 -0
  24. package/dist/browse/db/PostFTS.js.map +1 -0
  25. package/dist/browse/db/ProductFTS.d.ts +4 -0
  26. package/dist/browse/db/ProductFTS.js +163 -0
  27. package/dist/browse/db/ProductFTS.js.map +1 -0
  28. package/dist/browse/db/Update.js +3 -1
  29. package/dist/browse/db/Update.js.map +1 -1
  30. package/dist/browse/db/index.d.ts +12 -0
  31. package/dist/browse/db/updaters/DBUpdater_1_2_0.d.ts +2 -0
  32. package/dist/browse/db/updaters/DBUpdater_1_2_0.js +13 -0
  33. package/dist/browse/db/updaters/DBUpdater_1_2_0.js.map +1 -0
  34. package/dist/browse/server/Router.js +12 -1
  35. package/dist/browse/server/Router.js.map +1 -1
  36. package/dist/browse/server/handler/ContentAPIRequestHandler.d.ts +3 -0
  37. package/dist/browse/server/handler/ContentAPIRequestHandler.js +34 -2
  38. package/dist/browse/server/handler/ContentAPIRequestHandler.js.map +1 -1
  39. package/dist/browse/types/Campaign.d.ts +2 -0
  40. package/dist/browse/types/Campaign.js.map +1 -1
  41. package/dist/browse/types/Content.d.ts +43 -2
  42. package/dist/browse/types/Content.js.map +1 -1
  43. package/dist/browse/types/Filter.d.ts +6 -3
  44. package/dist/browse/types/Filter.js.map +1 -1
  45. package/dist/browse/web/assets/{index-b301OTnD.css → index-C4S8SMVg.css} +1 -1
  46. package/dist/browse/web/assets/index-D5kKPxpC.js +209 -0
  47. package/dist/browse/web/index.html +2 -2
  48. package/dist/cli/CLIOptions.js +20 -1
  49. package/dist/cli/CLIOptions.js.map +1 -1
  50. package/dist/cli/CommandLineParser.js +2 -1
  51. package/dist/cli/CommandLineParser.js.map +1 -1
  52. package/dist/cli/ConfigFileParser.js +8 -0
  53. package/dist/cli/ConfigFileParser.js.map +1 -1
  54. package/dist/cli/index.js +9 -1
  55. package/dist/cli/index.js.map +1 -1
  56. package/dist/downloaders/Bootstrap.d.ts +11 -1
  57. package/dist/downloaders/Bootstrap.js +14 -1
  58. package/dist/downloaders/Bootstrap.js.map +1 -1
  59. package/dist/downloaders/Downloader.d.ts +7 -3
  60. package/dist/downloaders/Downloader.js +159 -109
  61. package/dist/downloaders/Downloader.js.map +1 -1
  62. package/dist/downloaders/DownloaderEvent.d.ts +6 -6
  63. package/dist/downloaders/DownloaderEvent.js.map +1 -1
  64. package/dist/downloaders/DownloaderOptions.d.ts +14 -1
  65. package/dist/downloaders/DownloaderOptions.js +10 -0
  66. package/dist/downloaders/DownloaderOptions.js.map +1 -1
  67. package/dist/downloaders/InitialData.d.ts +16 -0
  68. package/dist/downloaders/InitialData.js +94 -0
  69. package/dist/downloaders/InitialData.js.map +1 -0
  70. package/dist/downloaders/PostDownloader.d.ts +11 -2
  71. package/dist/downloaders/PostDownloader.js +337 -277
  72. package/dist/downloaders/PostDownloader.js.map +1 -1
  73. package/dist/downloaders/PostsFetcher.d.ts +5 -5
  74. package/dist/downloaders/PostsFetcher.js +24 -75
  75. package/dist/downloaders/PostsFetcher.js.map +1 -1
  76. package/dist/downloaders/ProductDownloader.js +367 -165
  77. package/dist/downloaders/ProductDownloader.js.map +1 -1
  78. package/dist/downloaders/ProductsFetcher.d.ts +57 -0
  79. package/dist/downloaders/ProductsFetcher.js +331 -0
  80. package/dist/downloaders/ProductsFetcher.js.map +1 -0
  81. package/dist/downloaders/index.d.ts +1 -1
  82. package/dist/downloaders/index.js.map +1 -1
  83. package/dist/downloaders/task/DownloadTaskFactory.js +15 -1
  84. package/dist/downloaders/task/DownloadTaskFactory.js.map +1 -1
  85. package/dist/downloaders/templates/CollectionInfo.d.ts +2 -0
  86. package/dist/downloaders/templates/CollectionInfo.js +20 -0
  87. package/dist/downloaders/templates/CollectionInfo.js.map +1 -0
  88. package/dist/entities/Comment.d.ts +3 -3
  89. package/dist/entities/Comment.js.map +1 -1
  90. package/dist/entities/{Collection.d.ts → List.d.ts} +1 -1
  91. package/dist/entities/List.js +2 -0
  92. package/dist/entities/List.js.map +1 -0
  93. package/dist/entities/MediaItem.d.ts +17 -2
  94. package/dist/entities/MediaItem.js.map +1 -1
  95. package/dist/entities/Post.d.ts +34 -3
  96. package/dist/entities/Post.js.map +1 -1
  97. package/dist/entities/Product.d.ts +25 -0
  98. package/dist/entities/Product.js +6 -1
  99. package/dist/entities/Product.js.map +1 -1
  100. package/dist/entities/index.d.ts +1 -1
  101. package/dist/entities/index.js.map +1 -1
  102. package/dist/parsers/CommentParser.d.ts +3 -3
  103. package/dist/parsers/CommentParser.js.map +1 -1
  104. package/dist/parsers/Parser.d.ts +5 -1
  105. package/dist/parsers/Parser.js +70 -0
  106. package/dist/parsers/Parser.js.map +1 -1
  107. package/dist/parsers/PostParser.d.ts +2 -2
  108. package/dist/parsers/PostParser.js +34 -0
  109. package/dist/parsers/PostParser.js.map +1 -1
  110. package/dist/parsers/ProductParser.d.ts +3 -2
  111. package/dist/parsers/ProductParser.js +115 -49
  112. package/dist/parsers/ProductParser.js.map +1 -1
  113. package/dist/utils/FSHelper.d.ts +12 -8
  114. package/dist/utils/FSHelper.js +10 -0
  115. package/dist/utils/FSHelper.js.map +1 -1
  116. package/dist/utils/FilenameFormatHelper.d.ts +2 -1
  117. package/dist/utils/FilenameFormatHelper.js +14 -1
  118. package/dist/utils/FilenameFormatHelper.js.map +1 -1
  119. package/dist/utils/Misc.d.ts +2 -1
  120. package/dist/utils/Misc.js +23 -0
  121. package/dist/utils/Misc.js.map +1 -1
  122. package/dist/utils/URLHelper.d.ts +7 -0
  123. package/dist/utils/URLHelper.js +161 -3
  124. package/dist/utils/URLHelper.js.map +1 -1
  125. package/package.json +6 -3
  126. package/dist/browse/web/assets/index-C5gLqRAU.js +0 -209
  127. package/dist/entities/Collection.js +0 -2
  128. package/dist/entities/Collection.js.map +0 -1
package/README.md CHANGED
@@ -116,7 +116,12 @@ $ patreon-dl [OPTION]... URL
116
116
  #### Supported URL formats
117
117
 
118
118
  ```
119
- // Download a product
119
+ // Download products from a creator's shop
120
+ https://www.patreon.com/<creator>/shop
121
+ https://www.patreon.com/c/<creator>/shop
122
+ https://www.patreon.com/cw/<creator>/shop
123
+
124
+ // Download a single product
120
125
  https://www.patreon.com/<creator>/shop/<slug>-<product_id>
121
126
 
122
127
  // Download posts by creator
@@ -288,6 +293,15 @@ Note the URL shown in the output. Open this URL in a web browser to begin viewin
288
293
 
289
294
  ## Changelog
290
295
 
296
+ v3.5.0
297
+ - Add support for downloading from "shop" URLs (e.g. `https://www.patreon.com/<creator>/shop`). This will download all products from a creator's shop.
298
+ - Add `productsPublished` / `products.published.after` / `products.published.before` option to set publish date criteria of products included in download.
299
+ - Since `stopOn` / `stop.on` option now also applies to products, the `postPreviouslyDownloaded` and `postPublishDateOutOfRange` values have been deprecated in favor of `previouslyDownloaded` and `publishDateOutOfRange`, respectively.
300
+ - Add Collections support. Collection info is now saved when downloading posts. This means you can browse posts by collection. ([#107](https://github.com/patrickkfkan/patreon-dl/issues/107))
301
+ - (Browse) Add search functionality ([#106](https://github.com/patrickkfkan/patreon-dl/issues/106))
302
+ - Add Tags support. Tag info is now saved when downloading posts. This means you can filter posts by tag.
303
+ - Add `include.mediaThumbnails` option
304
+
291
305
  v3.4.0
292
306
  - Fix "no posts found" on "cw" pages ([patreon-dl-gui#30](https://github.com/patrickkfkan/patreon-dl-gui/issues/30))
293
307
  - Fix YouTube streams returning 403 error ([patreon-dl-gui#31](https://github.com/patrickkfkan/patreon-dl-gui/issues/31))
@@ -11,7 +11,7 @@ export declare function CampaignAPIMixin<TBase extends APIConstructor>(Base: TBa
11
11
  withCounts?: false;
12
12
  }): Campaign | null;
13
13
  getCampaign(params: GetCampaignParams): Campaign | CampaignWithCounts | null;
14
- "__#129@#sanitizeCampaign"(campaign: Campaign): void;
14
+ "__#131@#sanitizeCampaign"(campaign: Campaign): void;
15
15
  name: string;
16
16
  db: import("../db").DBInstance;
17
17
  logger?: import("../..").Logger | null;
@@ -1,13 +1,19 @@
1
1
  import { type APIConstructor } from ".";
2
2
  import { type Product, type Post } from "../../entities";
3
- import { type GetContentContext, type ContentType, type GetContentListParams } from "../types/Content.js";
3
+ import { type GetContentContext, type ContentType, type GetContentListParams, type GetCollectionListParams, type GetPostTagListParams } from "../types/Content.js";
4
4
  export declare function ContentAPIMixin<TBase extends APIConstructor>(Base: TBase): {
5
5
  new (...args: any[]): {
6
6
  getContentList<T extends ContentType>(params: GetContentListParams<T>): import("../types/Content.js").ContentList<T>;
7
7
  getPost(id: string): import("../types/Content.js").PostWithComments | null;
8
8
  getProduct(id: string): Product | null;
9
9
  getPreviousNextContent<T extends ContentType>(content: Post | Product, context: GetContentContext<T>): import("../types/Content.js").GetPreviousNextContentResult<T>;
10
- "__#130@#processPostContentInlineMedia"(post: Post): void;
10
+ getCollection(id: string): {
11
+ collection: import("../../entities").Collection;
12
+ campaignId: string;
13
+ } | null;
14
+ getCollectionList(params: GetCollectionListParams): import("../types/Content.js").CollectionList;
15
+ getPostTagList(params: GetPostTagListParams): import("../types/Content.js").PostTagList;
16
+ "__#132@#processPostContentInlineMedia"(post: Post): void;
11
17
  name: string;
12
18
  db: import("../db").DBInstance;
13
19
  logger?: import("../..").Logger | null;
@@ -8,6 +8,8 @@ import RawDataExtractor from '../web/utils/RawDataExtractor.js';
8
8
  import { URLHelper } from '../../utils/index.js';
9
9
  const DEFAULT_CONTENT_LIST_SIZE = 10;
10
10
  const DEFAULT_CONTENT_LIST_SORT_BY = 'a-z';
11
+ const DEFAULT_COLLECTION_LIST_SIZE = 10;
12
+ const DEFAULT_COLLECTION_LIST_SORT_BY = 'a-z';
11
13
  export function ContentAPIMixin(Base) {
12
14
  var _ContentAPI_instances, _ContentAPI_processPostContentInlineMedia, _a;
13
15
  return _a = class ContentAPI extends Base {
@@ -52,6 +54,24 @@ export function ContentAPIMixin(Base) {
52
54
  getPreviousNextContent(content, context) {
53
55
  return this.db.getPreviousNextContent(content, context);
54
56
  }
57
+ getCollection(id) {
58
+ return this.db.getCollection(id);
59
+ }
60
+ getCollectionList(params) {
61
+ const { search = '', sortBy = DEFAULT_COLLECTION_LIST_SORT_BY, limit = DEFAULT_COLLECTION_LIST_SIZE, offset = 0 } = params;
62
+ return this.db.getCollectionList({
63
+ campaign: params.campaign,
64
+ search,
65
+ sortBy,
66
+ limit,
67
+ offset
68
+ });
69
+ }
70
+ getPostTagList(params) {
71
+ return this.db.getPostTagList({
72
+ campaign: params.campaign,
73
+ });
74
+ }
55
75
  },
56
76
  _ContentAPI_instances = new WeakSet(),
57
77
  _ContentAPI_processPostContentInlineMedia = function _ContentAPI_processPostContentInlineMedia(post) {
@@ -1 +1 @@
1
- {"version":3,"file":"ContentAPIMixin.js","sourceRoot":"","sources":["../../../src/browse/api/ContentAPIMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { load as cheerioLoad } from 'cheerio';\nimport { type APIConstructor } from \".\";\nimport { type Product, type Post } from \"../../entities\";\nimport { type GetContentContext, type ContentListSortBy, type ContentType, type GetContentListParams } from \"../types/Content.js\";\nimport RawDataExtractor from '../web/utils/RawDataExtractor.js';\nimport { URLHelper } from '../../utils/index.js';\n\nconst DEFAULT_CONTENT_LIST_SIZE = 10;\nconst DEFAULT_CONTENT_LIST_SORT_BY: ContentListSortBy = 'a-z';\n\nexport function ContentAPIMixin<TBase extends APIConstructor>(Base: TBase) {\n return class ContentAPI extends Base {\n getContentList<T extends ContentType>(params: GetContentListParams<T>) {\n const { sortBy = DEFAULT_CONTENT_LIST_SORT_BY, limit = DEFAULT_CONTENT_LIST_SIZE, offset = 0 } = params;\n const list = this.db.getContentList({\n ...params,\n sortBy,\n limit,\n offset,\n });\n for (const item of list.items) {\n switch (item.type) {\n case 'post':\n this.#processPostContentInlineMedia(item);\n item.content = this.sanitizeHTML(item.content || '');\n break;\n case 'product': {\n const description = RawDataExtractor.getProductRichTextDescription(item);\n item.description = description ? this.sanitizeHTML(description) : null;\n break;\n }\n }\n }\n return list;\n }\n\n getPost(id: string) {\n const post = this.db.getContent(id, 'post');\n if (post) {\n this.#processPostContentInlineMedia(post);\n post.content = this.sanitizeHTML(post.content || '');\n }\n return post;\n }\n\n getProduct(id: string) {\n return this.db.getContent(id, 'product');\n }\n\n getPreviousNextContent<T extends ContentType>(content: Post | Product, context: GetContentContext<T>) {\n return this.db.getPreviousNextContent(content, context);\n }\n\n #processPostContentInlineMedia(post: Post) {\n const html = post.content || '';\n const hasImages = post.images.length > 0;\n const hasLinkedAttachments = post.linkedAttachments && post.linkedAttachments.length > 0;\n if (!html || (!hasImages && !hasLinkedAttachments)) {\n return;\n }\n\n const $ = cheerioLoad(html);\n const replacedMediaIds: string[] = [];\n let hasModified = false;\n\n if (hasImages) {\n $('img').each((_, _el) => {\n const el = $(_el);\n const id = el.attr('data-media-id');\n const matched = id ? post.images.find(img => img.id === id && img.downloaded) : null;\n const src = matched ? `/media/${matched.id}` : el.attr('src');\n const imgEl = $('<img>').attr('src', src);\n const aEl = $('<a>')\n .attr('href', src)\n .attr('class', 'lightgallery-item')\n .append(imgEl);\n const wrapperEl = $('<div>')\n .attr('class', 'post-card__inline-media-wrapper')\n .append(aEl);\n if (!matched) {\n const caption = \"(Externally hosted - not stored locally)\";\n wrapperEl.append(\n $('<span>').attr('class', 'post-card__inline-media-caption').append(caption)\n );\n }\n el.replaceWith(wrapperEl);\n if (id && matched) {\n replacedMediaIds.push(id);\n }\n });\n if (replacedMediaIds.length > 0) {\n hasModified = true;\n // Remove images that have been inlined\n post.images = post.images.filter((img) => !replacedMediaIds.includes(img.id));\n }\n }\n\n // Linked attachments\n if (hasLinkedAttachments) {\n $('a').each((_, _el) => {\n const aEl = $(_el);\n const href = aEl.attr('href') || '';\n const { validated, ownerId, mediaId } = URLHelper.isAttachmentLink(href);\n if (validated) {\n let modifiedPath: string | undefined;\n if (post.id !== ownerId) {\n const isDownloaded = post.linkedAttachments?.find((att) => att.postId === ownerId && att.mediaId === mediaId)?.downloadable?.downloaded;\n modifiedPath = isDownloaded && `/media/${mediaId}?lapid=${post.id}`;\n }\n else {\n const isDownloaded = post.attachments.find((att) => att.id === mediaId)?.downloaded;\n modifiedPath = isDownloaded && `/media/${mediaId}`;\n }\n if (modifiedPath) {\n aEl.attr('href', modifiedPath);\n hasModified = true;\n }\n }\n });\n }\n\n if (hasModified) {\n post.content = $.html();\n }\n }\n }\n}"]}
1
+ {"version":3,"file":"ContentAPIMixin.js","sourceRoot":"","sources":["../../../src/browse/api/ContentAPIMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { load as cheerioLoad } from 'cheerio';\nimport { type APIConstructor } from \".\";\nimport { type Product, type Post } from \"../../entities\";\nimport { type GetContentContext, type ContentListSortBy, type ContentType, type GetContentListParams, type GetCollectionListParams, type CollectionListSortBy, type GetPostTagListParams } from \"../types/Content.js\";\nimport RawDataExtractor from '../web/utils/RawDataExtractor.js';\nimport { URLHelper } from '../../utils/index.js';\n\nconst DEFAULT_CONTENT_LIST_SIZE = 10;\nconst DEFAULT_CONTENT_LIST_SORT_BY: ContentListSortBy = 'a-z';\n\nconst DEFAULT_COLLECTION_LIST_SIZE = 10;\nconst DEFAULT_COLLECTION_LIST_SORT_BY: CollectionListSortBy = 'a-z';\n\nexport function ContentAPIMixin<TBase extends APIConstructor>(Base: TBase) {\n return class ContentAPI extends Base {\n getContentList<T extends ContentType>(params: GetContentListParams<T>) {\n const { sortBy = DEFAULT_CONTENT_LIST_SORT_BY, limit = DEFAULT_CONTENT_LIST_SIZE, offset = 0 } = params;\n const list = this.db.getContentList({\n ...params,\n sortBy,\n limit,\n offset,\n });\n for (const item of list.items) {\n switch (item.type) {\n case 'post':\n this.#processPostContentInlineMedia(item);\n item.content = this.sanitizeHTML(item.content || '');\n break;\n case 'product': {\n const description = RawDataExtractor.getProductRichTextDescription(item);\n item.description = description ? this.sanitizeHTML(description) : null;\n break;\n }\n }\n }\n return list;\n }\n\n getPost(id: string) {\n const post = this.db.getContent(id, 'post');\n if (post) {\n this.#processPostContentInlineMedia(post);\n post.content = this.sanitizeHTML(post.content || '');\n }\n return post;\n }\n\n getProduct(id: string) {\n return this.db.getContent(id, 'product');\n }\n\n getPreviousNextContent<T extends ContentType>(content: Post | Product, context: GetContentContext<T>) {\n return this.db.getPreviousNextContent(content, context);\n }\n\n getCollection(id: string) {\n return this.db.getCollection(id);\n }\n\n getCollectionList(params: GetCollectionListParams) {\n const {\n search = '',\n sortBy = DEFAULT_COLLECTION_LIST_SORT_BY,\n limit = DEFAULT_COLLECTION_LIST_SIZE,\n offset = 0\n } = params;\n return this.db.getCollectionList({\n campaign: params.campaign,\n search,\n sortBy,\n limit,\n offset\n });\n }\n\n getPostTagList(params: GetPostTagListParams) {\n return this.db.getPostTagList({\n campaign: params.campaign,\n });\n }\n\n #processPostContentInlineMedia(post: Post) {\n const html = post.content || '';\n const hasImages = post.images.length > 0;\n const hasLinkedAttachments = post.linkedAttachments && post.linkedAttachments.length > 0;\n if (!html || (!hasImages && !hasLinkedAttachments)) {\n return;\n }\n\n const $ = cheerioLoad(html);\n const replacedMediaIds: string[] = [];\n let hasModified = false;\n\n if (hasImages) {\n $('img').each((_, _el) => {\n const el = $(_el);\n const id = el.attr('data-media-id');\n const matched = id ? post.images.find(img => img.id === id && img.downloaded) : null;\n const src = matched ? `/media/${matched.id}` : el.attr('src');\n const imgEl = $('<img>').attr('src', src);\n const aEl = $('<a>')\n .attr('href', src)\n .attr('class', 'lightgallery-item')\n .append(imgEl);\n const wrapperEl = $('<div>')\n .attr('class', 'post-card__inline-media-wrapper')\n .append(aEl);\n if (!matched) {\n const caption = \"(Externally hosted - not stored locally)\";\n wrapperEl.append(\n $('<span>').attr('class', 'post-card__inline-media-caption').append(caption)\n );\n }\n el.replaceWith(wrapperEl);\n if (id && matched) {\n replacedMediaIds.push(id);\n }\n });\n if (replacedMediaIds.length > 0) {\n hasModified = true;\n // Remove images that have been inlined\n post.images = post.images.filter((img) => !replacedMediaIds.includes(img.id));\n }\n }\n\n // Linked attachments\n if (hasLinkedAttachments) {\n $('a').each((_, _el) => {\n const aEl = $(_el);\n const href = aEl.attr('href') || '';\n const { validated, ownerId, mediaId } = URLHelper.isAttachmentLink(href);\n if (validated) {\n let modifiedPath: string | undefined;\n if (post.id !== ownerId) {\n const isDownloaded = post.linkedAttachments?.find((att) => att.postId === ownerId && att.mediaId === mediaId)?.downloadable?.downloaded;\n modifiedPath = isDownloaded && `/media/${mediaId}?lapid=${post.id}`;\n }\n else {\n const isDownloaded = post.attachments.find((att) => att.id === mediaId)?.downloaded;\n modifiedPath = isDownloaded && `/media/${mediaId}`;\n }\n if (modifiedPath) {\n aEl.attr('href', modifiedPath);\n hasModified = true;\n }\n }\n });\n }\n\n if (hasModified) {\n post.content = $.html();\n }\n }\n }\n}"]}
@@ -3,7 +3,7 @@ import { type FilterData, type MediaFilterSearchParams, type PostFilterSearchPar
3
3
  export declare function FilterAPIMixin<TBase extends APIConstructor>(Base: TBase): {
4
4
  new (...args: any[]): {
5
5
  getPostFilterData(campaignId: string): FilterData<PostFilterSearchParams>;
6
- "__#131@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
6
+ "__#133@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
7
7
  getProductFilterData(campaignId: string): FilterData<ProductFilterSearchParams>;
8
8
  getMediaFilterData(campaignId: string): FilterData<MediaFilterSearchParams>;
9
9
  name: string;
@@ -134,7 +134,27 @@ export function FilterAPIMixin(Base) {
134
134
  searchParam: 'date_published',
135
135
  options: datePublishedOptions
136
136
  });
137
- return { sections };
137
+ const { tags } = this.db.getPostTagList({ campaign: campaignId });
138
+ if (tags.length > 0) {
139
+ const tagOptions = tags.map((tag) => ({
140
+ title: tag.value,
141
+ value: tag.id
142
+ }));
143
+ sections.push({
144
+ title: 'Tagged',
145
+ displayHint: 'pill_small',
146
+ searchParam: 'tag_id',
147
+ options: tagOptions
148
+ });
149
+ }
150
+ return {
151
+ sections,
152
+ external: [
153
+ {
154
+ searchParam: 'search'
155
+ }
156
+ ]
157
+ };
138
158
  }
139
159
  getProductFilterData(campaignId) {
140
160
  const productCountByYear = this.db.getContentCountByDate('product', 'year', {
@@ -208,7 +228,14 @@ export function FilterAPIMixin(Base) {
208
228
  searchParam: 'date_published',
209
229
  options: datePublishedOptions
210
230
  });
211
- return { sections };
231
+ return {
232
+ sections,
233
+ external: [
234
+ {
235
+ searchParam: 'search'
236
+ }
237
+ ]
238
+ };
212
239
  }
213
240
  getMediaFilterData(campaignId) {
214
241
  const mediaCountByTier = this.db.getMediaCountByTier(campaignId);
@@ -1 +1 @@
1
- {"version":3,"file":"FilterAPIMixin.js","sourceRoot":"","sources":["../../../src/browse/api/FilterAPIMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { type APIConstructor } from \".\";\nimport { PostType } from \"../../entities/Post.js\";\nimport { type FilterData, type FilterOption, type FilterSection, type MediaFilterSearchParams, type PostFilterSearchParams, type ProductFilterSearchParams } from \"../types/Filter.js\";\nimport { type ContentListSortBy } from \"../types/Content.js\";\nimport { type MediaListSortBy } from \"../types/Media.js\";\n\nexport function FilterAPIMixin<TBase extends APIConstructor>(Base: TBase) {\n return class FilterAPI extends Base {\n getPostFilterData(\n campaignId: string\n ): FilterData<PostFilterSearchParams> {\n const postCountByTier = this.db.getPostCountByTier(campaignId);\n const postCountByType = this.db.getPostCountByType(campaignId);\n const postCountByYear = this.db.getContentCountByDate('post', 'year', {\n campaign: campaignId\n });\n const postCountThisMonth = (this.db.getContentCountByDate('post', 'month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<PostFilterSearchParams>[] = [];\n\n const postTypeRecords = postCountByType.map<FilterOption & { count: number; }>(({ postType, count }) => ({\n title: this.#getPostTypeTitle(postType),\n count,\n value: postType\n }))\n .reduce<Record<string, { count: number, value: string; }>>((result, option) => {\n if (option.value) {\n if (result[option.title]) {\n result[option.title].count += option.count;\n result[option.title].value += `,${option.value}`;\n }\n else {\n result[option.title] = { \n count: option.count,\n value: option.value\n };\n }\n }\n return result;\n }, {});\n const postTypeOptions: FilterOption[] = [];\n for (const [title, { count, value }] of Object.entries(postTypeRecords)) {\n postTypeOptions.push({\n title: `${title} (${count})`,\n value\n });\n }\n if (postTypeOptions.length > 0) {\n sections.push({\n title: 'Post type',\n displayHint: 'pill',\n searchParam: 'post_types',\n options: postTypeOptions\n });\n }\n\n const postAccessOptions: FilterOption[] = [\n {\n title: 'Posts you have access to',\n value: 'true',\n },\n {\n title: 'All posts',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Post access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: postAccessOptions\n });\n\n const tierOptions = postCountByTier.map<FilterOption>(({tierId, title, count}) => ({\n title: `${title || (tierId === '-1' ? 'Public' : title)} (${count})`,\n value: tierId,\n }));\n tierOptions.unshift({\n title: 'Any tier',\n value: null,\n isDefault: true\n });\n sections.push({\n displayHint: 'list',\n searchParam: 'tier_ids',\n options: tierOptions\n });\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies ContentListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies ContentListSortBy,\n },\n {\n title: 'A-Z',\n value: 'a-z' satisfies ContentListSortBy,\n },\n {\n title: 'Z-A',\n value: 'z-a' satisfies ContentListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = postCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (postCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month (${postCountThisMonth.count})`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n return { sections };\n }\n\n #getPostTypeTitle(postType: string) {\n switch (postType) {\n case PostType.Audio:\n return 'Audio';\n case PostType.Image:\n return 'Image';\n case PostType.Link:\n return 'Link';\n case PostType.Podcast:\n return 'Podcast';\n case PostType.Poll:\n return 'Poll';\n case PostType.Text:\n return 'Text';\n case PostType.Video:\n case PostType.VideoEmbed:\n return 'Video';\n default:\n return 'Other';\n }\n }\n\n getProductFilterData(\n campaignId: string\n ): FilterData<ProductFilterSearchParams> {\n const productCountByYear = this.db.getContentCountByDate('product', 'year', {\n campaign: campaignId\n });\n const productCountThisMonth = (this.db.getContentCountByDate('product', 'month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<ProductFilterSearchParams>[] = [];\n \n const productAccessOptions: FilterOption[] = [\n {\n title: 'Products you have access to',\n value: 'true',\n },\n {\n title: 'All products',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Product access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: productAccessOptions\n });\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies ContentListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies ContentListSortBy,\n },\n {\n title: 'A-Z',\n value: 'a-z' satisfies ContentListSortBy,\n },\n {\n title: 'Z-A',\n value: 'z-a' satisfies ContentListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = productCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (productCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month ${productCountThisMonth.count}`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n return { sections };\n }\n\n getMediaFilterData(\n campaignId: string\n ): FilterData<MediaFilterSearchParams> {\n const mediaCountByTier = this.db.getMediaCountByTier(campaignId);\n const mediaCountByType = this.db.getMediaCountByContentType(campaignId);\n const mediaCountByYear = this.db.getMediaCountByDate('year', {\n campaign: campaignId\n });\n const postCountThisMonth = (this.db.getMediaCountByDate('month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<MediaFilterSearchParams>[] = [];\n\n const sourceTypeRecords = mediaCountByType.map<FilterOption & { count: number; }>(({ contentType, count }) => ({\n title: contentType === 'post' ? 'Posts' : 'Products',\n count,\n value: contentType\n }))\n .reduce<Record<string, { count: number, value: string; }>>((result, option) => {\n if (option.value) {\n if (result[option.title]) {\n result[option.title].count += option.count;\n result[option.title].value += `,${option.value}`;\n }\n else {\n result[option.title] = { \n count: option.count,\n value: option.value\n };\n }\n }\n return result;\n }, {});\n const sourceTypeOptions: FilterOption[] = [];\n for (const [title, { count, value }] of Object.entries(sourceTypeRecords)) {\n sourceTypeOptions.push({\n title: `${title} (${count})`,\n value\n });\n }\n if (sourceTypeOptions.length > 0) {\n sections.push({\n title: 'Show media from',\n displayHint: 'pill',\n searchParam: 'source_type',\n options: sourceTypeOptions\n });\n }\n\n const mediaAccessOptions: FilterOption[] = [\n {\n title: 'Media you have access to',\n value: 'true',\n },\n {\n title: 'All media',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Media access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: mediaAccessOptions\n });\n\n if (sourceTypeOptions.find((o) => o.value === 'post')) {\n const tierOptions = mediaCountByTier.map<FilterOption>(({tierId, title, count}) => ({\n title: `${title || (tierId === '-1' ? 'Public' : title)} (${count})`,\n value: tierId,\n }));\n tierOptions.unshift({\n title: 'Any tier',\n value: null,\n isDefault: true\n });\n const tierSection: FilterSection<MediaFilterSearchParams> = {\n displayHint: 'list',\n searchParam: 'tier_ids',\n options: tierOptions\n };\n const hasProductSourceType = sourceTypeOptions.find((o) => o.value === 'product');\n if (hasProductSourceType) {\n tierSection.enableCondition = {\n searchParam: 'source_type',\n condition: 'not',\n value: 'post'\n };\n }\n sections.push(tierSection);\n }\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies MediaListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies MediaListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = mediaCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (postCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month (${postCountThisMonth.count})`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n return { sections };\n }\n }\n}"]}
1
+ {"version":3,"file":"FilterAPIMixin.js","sourceRoot":"","sources":["../../../src/browse/api/FilterAPIMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { type APIConstructor } from \".\";\nimport { PostType } from \"../../entities/Post.js\";\nimport { type FilterData, type FilterOption, type FilterSection, type MediaFilterSearchParams, type PostFilterSearchParams, type ProductFilterSearchParams } from \"../types/Filter.js\";\nimport { type ContentListSortBy } from \"../types/Content.js\";\nimport { type MediaListSortBy } from \"../types/Media.js\";\n\nexport function FilterAPIMixin<TBase extends APIConstructor>(Base: TBase) {\n return class FilterAPI extends Base {\n getPostFilterData(\n campaignId: string\n ): FilterData<PostFilterSearchParams> {\n const postCountByTier = this.db.getPostCountByTier(campaignId);\n const postCountByType = this.db.getPostCountByType(campaignId);\n const postCountByYear = this.db.getContentCountByDate('post', 'year', {\n campaign: campaignId\n });\n const postCountThisMonth = (this.db.getContentCountByDate('post', 'month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<PostFilterSearchParams>[] = [];\n\n const postTypeRecords = postCountByType.map<FilterOption & { count: number; }>(({ postType, count }) => ({\n title: this.#getPostTypeTitle(postType),\n count,\n value: postType\n }))\n .reduce<Record<string, { count: number, value: string; }>>((result, option) => {\n if (option.value) {\n if (result[option.title]) {\n result[option.title].count += option.count;\n result[option.title].value += `,${option.value}`;\n }\n else {\n result[option.title] = { \n count: option.count,\n value: option.value\n };\n }\n }\n return result;\n }, {});\n const postTypeOptions: FilterOption[] = [];\n for (const [title, { count, value }] of Object.entries(postTypeRecords)) {\n postTypeOptions.push({\n title: `${title} (${count})`,\n value\n });\n }\n if (postTypeOptions.length > 0) {\n sections.push({\n title: 'Post type',\n displayHint: 'pill',\n searchParam: 'post_types',\n options: postTypeOptions\n });\n }\n\n const postAccessOptions: FilterOption[] = [\n {\n title: 'Posts you have access to',\n value: 'true',\n },\n {\n title: 'All posts',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Post access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: postAccessOptions\n });\n\n const tierOptions = postCountByTier.map<FilterOption>(({tierId, title, count}) => ({\n title: `${title || (tierId === '-1' ? 'Public' : title)} (${count})`,\n value: tierId,\n }));\n tierOptions.unshift({\n title: 'Any tier',\n value: null,\n isDefault: true\n });\n sections.push({\n displayHint: 'list',\n searchParam: 'tier_ids',\n options: tierOptions\n });\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies ContentListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies ContentListSortBy,\n },\n {\n title: 'A-Z',\n value: 'a-z' satisfies ContentListSortBy,\n },\n {\n title: 'Z-A',\n value: 'z-a' satisfies ContentListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = postCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (postCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month (${postCountThisMonth.count})`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n const { tags } = this.db.getPostTagList({ campaign: campaignId });\n if (tags.length > 0) {\n const tagOptions: FilterOption[] = tags.map((tag) => ({\n title: tag.value,\n value: tag.id\n }));\n sections.push({\n title: 'Tagged',\n displayHint: 'pill_small',\n searchParam: 'tag_id',\n options: tagOptions\n });\n }\n\n return {\n sections,\n external: [\n {\n searchParam: 'search'\n }\n ]\n };\n }\n\n #getPostTypeTitle(postType: string) {\n switch (postType) {\n case PostType.Audio:\n return 'Audio';\n case PostType.Image:\n return 'Image';\n case PostType.Link:\n return 'Link';\n case PostType.Podcast:\n return 'Podcast';\n case PostType.Poll:\n return 'Poll';\n case PostType.Text:\n return 'Text';\n case PostType.Video:\n case PostType.VideoEmbed:\n return 'Video';\n default:\n return 'Other';\n }\n }\n\n getProductFilterData(\n campaignId: string\n ): FilterData<ProductFilterSearchParams> {\n const productCountByYear = this.db.getContentCountByDate('product', 'year', {\n campaign: campaignId\n });\n const productCountThisMonth = (this.db.getContentCountByDate('product', 'month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<ProductFilterSearchParams>[] = [];\n \n const productAccessOptions: FilterOption[] = [\n {\n title: 'Products you have access to',\n value: 'true',\n },\n {\n title: 'All products',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Product access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: productAccessOptions\n });\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies ContentListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies ContentListSortBy,\n },\n {\n title: 'A-Z',\n value: 'a-z' satisfies ContentListSortBy,\n },\n {\n title: 'Z-A',\n value: 'z-a' satisfies ContentListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = productCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (productCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month ${productCountThisMonth.count}`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n return {\n sections,\n external: [\n {\n searchParam: 'search'\n }\n ]\n };\n }\n\n getMediaFilterData(\n campaignId: string\n ): FilterData<MediaFilterSearchParams> {\n const mediaCountByTier = this.db.getMediaCountByTier(campaignId);\n const mediaCountByType = this.db.getMediaCountByContentType(campaignId);\n const mediaCountByYear = this.db.getMediaCountByDate('year', {\n campaign: campaignId\n });\n const postCountThisMonth = (this.db.getMediaCountByDate('month', {\n campaign: campaignId,\n date: new Date()\n }))[0];\n\n const sections: FilterSection<MediaFilterSearchParams>[] = [];\n\n const sourceTypeRecords = mediaCountByType.map<FilterOption & { count: number; }>(({ contentType, count }) => ({\n title: contentType === 'post' ? 'Posts' : 'Products',\n count,\n value: contentType\n }))\n .reduce<Record<string, { count: number, value: string; }>>((result, option) => {\n if (option.value) {\n if (result[option.title]) {\n result[option.title].count += option.count;\n result[option.title].value += `,${option.value}`;\n }\n else {\n result[option.title] = { \n count: option.count,\n value: option.value\n };\n }\n }\n return result;\n }, {});\n const sourceTypeOptions: FilterOption[] = [];\n for (const [title, { count, value }] of Object.entries(sourceTypeRecords)) {\n sourceTypeOptions.push({\n title: `${title} (${count})`,\n value\n });\n }\n if (sourceTypeOptions.length > 0) {\n sections.push({\n title: 'Show media from',\n displayHint: 'pill',\n searchParam: 'source_type',\n options: sourceTypeOptions\n });\n }\n\n const mediaAccessOptions: FilterOption[] = [\n {\n title: 'Media you have access to',\n value: 'true',\n },\n {\n title: 'All media',\n value: null,\n isDefault: true,\n }\n ];\n sections.push({\n title: 'Media access',\n displayHint: 'list',\n searchParam: 'is_viewable',\n options: mediaAccessOptions\n });\n\n if (sourceTypeOptions.find((o) => o.value === 'post')) {\n const tierOptions = mediaCountByTier.map<FilterOption>(({tierId, title, count}) => ({\n title: `${title || (tierId === '-1' ? 'Public' : title)} (${count})`,\n value: tierId,\n }));\n tierOptions.unshift({\n title: 'Any tier',\n value: null,\n isDefault: true\n });\n const tierSection: FilterSection<MediaFilterSearchParams> = {\n displayHint: 'list',\n searchParam: 'tier_ids',\n options: tierOptions\n };\n const hasProductSourceType = sourceTypeOptions.find((o) => o.value === 'product');\n if (hasProductSourceType) {\n tierSection.enableCondition = {\n searchParam: 'source_type',\n condition: 'not',\n value: 'post'\n };\n }\n sections.push(tierSection);\n }\n\n const sortByOptions: FilterOption[] = [\n {\n title: 'Latest',\n value: 'latest' satisfies MediaListSortBy,\n isDefault: true\n },\n {\n title: 'Oldest',\n value: 'oldest' satisfies MediaListSortBy,\n }\n ];\n sections.push({\n title: 'Sort by',\n displayHint: 'list',\n searchParam: 'sort_by',\n options: sortByOptions\n });\n\n const datePublishedOptions = mediaCountByYear.map<FilterOption>(({dt, count}) => ({\n title: `${dt} (${count})`,\n value: dt,\n }));\n if (postCountThisMonth?.count > 0) {\n datePublishedOptions.unshift({\n title: `This month (${postCountThisMonth.count})`,\n value: 'this_month',\n });\n }\n datePublishedOptions.unshift({\n title: 'Any date',\n value: null,\n isDefault: true\n });\n sections.push({\n title: 'Date published',\n displayHint: 'list',\n searchParam: 'date_published',\n options: datePublishedOptions\n });\n\n return { sections };\n }\n }\n}"]}
@@ -10,7 +10,7 @@ export declare class APIBase {
10
10
  constructor(db: DBInstance, logger?: Logger | null);
11
11
  static getInstance(db: DBInstance, logger?: Logger | null): {
12
12
  getPostFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").PostFilterSearchParams>;
13
- "__#131@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
13
+ "__#133@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
14
14
  getProductFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").ProductFilterSearchParams>;
15
15
  getMediaFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").MediaFilterSearchParams>;
16
16
  name: string;
@@ -43,7 +43,13 @@ export declare class APIBase {
43
43
  getPost(id: string): import("../types/Content.js").PostWithComments | null;
44
44
  getProduct(id: string): import("../../index.js").Product | null;
45
45
  getPreviousNextContent<T extends import("../types/Content.js").ContentType>(content: import("../../index.js").Post | import("../../index.js").Product, context: import("../types/Content.js").GetContentContext<T>): import("../types/Content.js").GetPreviousNextContentResult<T>;
46
- "__#130@#processPostContentInlineMedia"(post: import("../../index.js").Post): void;
46
+ getCollection(id: string): {
47
+ collection: import("../../index.js").Collection;
48
+ campaignId: string;
49
+ } | null;
50
+ getCollectionList(params: import("../types/Content.js").GetCollectionListParams): import("../types/Content.js").CollectionList;
51
+ getPostTagList(params: import("../types/Content.js").GetPostTagListParams): import("../types/Content.js").PostTagList;
52
+ "__#132@#processPostContentInlineMedia"(post: import("../../index.js").Post): void;
47
53
  name: string;
48
54
  db: DBInstance;
49
55
  logger?: Logger | null;
@@ -58,7 +64,7 @@ export declare class APIBase {
58
64
  withCounts?: false;
59
65
  }): import("../../index.js").Campaign | null;
60
66
  getCampaign(params: import("../types/Campaign.js").GetCampaignParams): import("../../index.js").Campaign | import("../types/Campaign.js").CampaignWithCounts | null;
61
- "__#129@#sanitizeCampaign"(campaign: import("../../index.js").Campaign): void;
67
+ "__#131@#sanitizeCampaign"(campaign: import("../../index.js").Campaign): void;
62
68
  name: string;
63
69
  db: DBInstance;
64
70
  logger?: Logger | null;
@@ -71,7 +77,7 @@ export declare class APIBase {
71
77
  declare const API: {
72
78
  new (...args: any[]): {
73
79
  getPostFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").PostFilterSearchParams>;
74
- "__#131@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
80
+ "__#133@#getPostTypeTitle"(postType: string): "Link" | "Audio" | "Image" | "Video" | "Other" | "Text" | "Podcast" | "Poll";
75
81
  getProductFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").ProductFilterSearchParams>;
76
82
  getMediaFilterData(campaignId: string): import("../types/Filter.js").FilterData<import("../types/Filter.js").MediaFilterSearchParams>;
77
83
  name: string;
@@ -110,7 +116,13 @@ declare const API: {
110
116
  getPost(id: string): import("../types/Content.js").PostWithComments | null;
111
117
  getProduct(id: string): import("../../index.js").Product | null;
112
118
  getPreviousNextContent<T extends import("../types/Content.js").ContentType>(content: import("../../index.js").Post | import("../../index.js").Product, context: import("../types/Content.js").GetContentContext<T>): import("../types/Content.js").GetPreviousNextContentResult<T>;
113
- "__#130@#processPostContentInlineMedia"(post: import("../../index.js").Post): void;
119
+ getCollection(id: string): {
120
+ collection: import("../../index.js").Collection;
121
+ campaignId: string;
122
+ } | null;
123
+ getCollectionList(params: import("../types/Content.js").GetCollectionListParams): import("../types/Content.js").CollectionList;
124
+ getPostTagList(params: import("../types/Content.js").GetPostTagListParams): import("../types/Content.js").PostTagList;
125
+ "__#132@#processPostContentInlineMedia"(post: import("../../index.js").Post): void;
114
126
  name: string;
115
127
  db: DBInstance;
116
128
  logger?: Logger | null;
@@ -127,7 +139,7 @@ declare const API: {
127
139
  withCounts?: false;
128
140
  }): import("../../index.js").Campaign | null;
129
141
  getCampaign(params: import("../types/Campaign.js").GetCampaignParams): import("../../index.js").Campaign | import("../types/Campaign.js").CampaignWithCounts | null;
130
- "__#129@#sanitizeCampaign"(campaign: import("../../index.js").Campaign): void;
142
+ "__#131@#sanitizeCampaign"(campaign: import("../../index.js").Campaign): void;
131
143
  name: string;
132
144
  db: DBInstance;
133
145
  logger?: Logger | null;
@@ -197,6 +197,12 @@ export function CampaignDBMixin(Base) {
197
197
  select: 'COUNT(content_media.media_id) AS media_count, content_media.campaign_id',
198
198
  groupBy: 'content_media.campaign_id'
199
199
  });
200
+ const collectionCountSelect = `
201
+ SELECT
202
+ COUNT(collection_id) AS collection_count,
203
+ campaign_id
204
+ FROM collection GROUP BY campaign_id
205
+ `;
200
206
  try {
201
207
  const rows = this.all(`
202
208
  SELECT
@@ -204,17 +210,20 @@ export function CampaignDBMixin(Base) {
204
210
  IFNULL(post_count, 0) post_count,
205
211
  IFNULL(product_count, 0) product_count,
206
212
  IFNULL(media_count, 0) media_count,
213
+ IFNULL(collection_count, 0) AS collection_count,
207
214
  COALESCE(post_count, 0) + COALESCE(product_count, 0) content_count
208
215
  FROM campaign
209
216
  LEFT JOIN (${postCountSelect}) postc ON postc.campaign_id = campaign.campaign_id
210
217
  LEFT JOIN (${productCountSelect}) productc ON productc.campaign_id = campaign.campaign_id
211
218
  LEFT JOIN (${mediaCountSelect}) mc ON mc.campaign_id = campaign.campaign_id
219
+ LEFT JOIN (${collectionCountSelect}) cc ON cc.campaign_id = campaign.campaign_id
212
220
  ${orderByClause}
213
221
  ${limitOffsetClause}
214
222
  `, [...limitOffsetValues]);
215
223
  const campaigns = rows.map((row) => ({
216
224
  ...JSON.parse(row.details),
217
225
  postCount: (row.post_count || 0),
226
+ collectionCount: (row.collection_count || 0),
218
227
  productCount: (row.product_count || 0),
219
228
  mediaCount: (row.media_count || 0)
220
229
  }));
@@ -294,18 +303,21 @@ export function CampaignDBMixin(Base) {
294
303
  campaign.details,
295
304
  IFNULL(media_count, 0) AS media_count,
296
305
  IFNULL(post_count, 0) AS post_count,
297
- IFNULL(product_count, 0) AS product_count
306
+ IFNULL(product_count, 0) AS product_count,
307
+ IFNULL(collection_count, 0) AS collection_count
298
308
  FROM
299
309
  campaign
300
310
  ${joinUser}
301
311
  LEFT JOIN (SELECT COUNT(content_id) AS post_count, campaign_id FROM content WHERE content_type = 'post' GROUP BY campaign_id) postc ON postc.campaign_id = campaign.campaign_id
302
312
  LEFT JOIN (SELECT COUNT(content_id) AS product_count, campaign_id FROM content WHERE content_type = 'product' GROUP BY campaign_id) productc ON productc.campaign_id = campaign.campaign_id
303
313
  LEFT JOIN (SELECT COUNT(media_id) AS media_count, campaign_id FROM content_media GROUP BY campaign_id) mc ON mc.campaign_id = campaign.campaign_id
314
+ LEFT JOIN (SELECT COUNT(collection_id) AS collection_count, campaign_id FROM collection GROUP BY campaign_id) collectionc ON collectionc.campaign_id = campaign.campaign_id
304
315
  ${whereClause}
305
316
  `, [...whereValues]);
306
317
  return row ? {
307
318
  ...JSON.parse(row.details),
308
319
  postCount: (row.post_count || 0),
320
+ collectionCount: (row.collection_count || 0),
309
321
  productCount: (row.product_count || 0),
310
322
  mediaCount: (row.media_count || 0)
311
323
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CampaignDBMixin.js","sourceRoot":"","sources":["../../../src/browse/db/CampaignDBMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Reward } from '../../entities/Reward.js';\nimport { type Campaign } from '../../entities/Campaign.js';\nimport { type UserDBConstructor } from './UserDBMixin.js';\nimport { type CampaignList, type CampaignWithCounts, type GetCampaignListParams, type GetCampaignParams } from '../types/Campaign.js';\n\nexport type CampaignDBConstructor = new (\n ...args: any[]\n) => InstanceType<ReturnType<typeof CampaignDBMixin<UserDBConstructor>>>;\n\nconst NULL_CAMPAIGN: Campaign = {\n type: 'campaign',\n id: '-1',\n name: '',\n createdAt: null,\n publishedAt: null,\n avatarImage: {\n type: 'image',\n id: '-1',\n filename: 'avatar',\n createdAt: null,\n mimeType: null,\n downloadURL: null,\n imageType: 'default',\n imageURLs: {\n default: null,\n defaultSmall: null,\n original: null,\n thumbnail: null,\n thumbnailLarge: null,\n thumbnailSmall: null\n },\n thumbnailURL: null\n },\n coverPhoto: {\n type: 'image',\n id: 'campaign:-1:cover',\n filename: 'cover-photo',\n mimeType: null,\n imageType: 'campaignCoverPhoto',\n imageURLs: {\n large: null,\n medium: null,\n small: null,\n xlarge: null,\n xsmall: null\n }\n },\n summary: null,\n url: null,\n currency: null,\n rewards: [],\n creator: null,\n raw: {}\n}\n\nexport function CampaignDBMixin<TBase extends UserDBConstructor>(Base: TBase) {\n return class CampaignDB extends Base {\n saveCampaign(campaign: Campaign | null, downloadDate: Date, overwriteIfExists = true) {\n if (!campaign) {\n campaign = NULL_CAMPAIGN; \n }\n this.log('debug', `Save campaign #${campaign.id} (${campaign.name}) to DB`);\n try {\n const campaignExists = this.checkCampaignExists(campaign.id);\n if (campaignExists && !overwriteIfExists) {\n return;\n }\n\n this.exec('BEGIN TRANSACTION');\n\n // Save creator\n this.saveUser(campaign.creator);\n\n this.saveMedia(campaign.avatarImage);\n this.saveMedia(campaign.coverPhoto);\n\n if (!campaignExists) {\n this.run(\n `\n INSERT INTO campaign (\n campaign_id,\n creator_id,\n campaign_name,\n last_download,\n details\n )\n VALUES (?, ?, ?, ?, ?)\n `,\n [\n campaign.id,\n campaign.creator?.id || '-1',\n campaign.name,\n downloadDate.getTime(),\n JSON.stringify(campaign)\n ]\n );\n } else {\n this.log('debug', `Campaign #${campaign.id} already exists in DB - update record`);\n this.run(`\n UPDATE campaign\n SET\n creator_id = ?,\n campaign_name = ?,\n last_download = ?,\n details = ?\n WHERE campaign_id = ?\n `,\n [\n campaign.creator?.id || '-1',\n campaign.name,\n downloadDate.getTime(),\n JSON.stringify(campaign),\n campaign.id\n ]\n );\n }\n\n // Save rewards\n this.#saveRewards(campaign);\n\n this.exec('COMMIT');\n } catch (error) {\n this.log(\n 'error',\n `Failed to save campaign #${campaign.id} (${campaign.name}) to DB:`,\n error\n );\n this.exec('ROLLBACK');\n }\n }\n\n getCampaign(params: GetCampaignParams)\n {\n const { id, vanity, withCounts = false } = params;\n if (id) {\n this.log('debug', `Get campaign by ID \"${id}\" from DB`);\n }\n else if (vanity) {\n this.log('debug', `Get campaign by vanity \"${vanity}\" from DB`);\n }\n if (!id && !vanity) {\n throw Error('Invalid params: expecting \"id\" or \"vanity\" but got none.')\n }\n if (withCounts) {\n return this.#getCampaignWithCounts(params);\n }\n let result;\n if (id) {\n result = this.get(\n `SELECT details FROM campaign WHERE campaign_id = ?`,\n [params.id]\n );\n }\n else {\n result = this.get(\n `\n SELECT campaign.details\n FROM campaign\n LEFT JOIN user ON user.user_id = campaign.creator_id\n WHERE user.vanity = ?;\n `,\n [params.vanity]\n );\n }\n return result ? JSON.parse(result.details) as Campaign : null;\n }\n\n #saveRewards(campaign: Campaign) {\n if (campaign.id === NULL_CAMPAIGN.id) {\n this.log('warn', 'Skip save rewards to DB because campaign is null');\n return;\n }\n // Clear existing rewards for campaign\n this.log('debug', `Clear existing rewards in DB for campaign #${campaign.id} before saving current ones`);\n this.run(`DELETE FROM reward WHERE campaign_id = ?`, [\n campaign.id\n ]);\n campaign.rewards.forEach((reward) => this.#doSaveReward(campaign, reward));\n }\n\n #doSaveReward(campaign: Campaign, reward: Reward) {\n this.log('debug', `Add reward #${reward.id} (${reward.title}) to DB`);\n try {\n if (reward.image) {\n this.saveMedia(reward.image);\n }\n this.run(`\n INSERT INTO reward (\n reward_id,\n campaign_id,\n title,\n details\n )\n VALUES (?, ?, ?, ?)\n `,\n [\n reward.id,\n campaign.id,\n reward.title,\n JSON.stringify(reward)\n ]);\n }\n catch (error) {\n this.log(\n 'error',\n `Failed to save reward #${reward.id} (${reward.title}) to DB:`,\n error\n );\n throw error;\n }\n }\n\n getCampaignList(params: GetCampaignListParams): CampaignList {\n const { sortBy, limit, offset } = params;\n this.log('debug', 'Get campaigns from DB:', params);\n let orderByClause: string;\n switch (sortBy) {\n case 'a-z':\n orderByClause = 'campaign_name ASC';\n break;\n case 'z-a':\n orderByClause = 'campaign_name DESC';\n break;\n case 'most_content':\n orderByClause = 'content_count DESC';\n break;\n case 'most_media':\n orderByClause = 'media_count DESC';\n break;\n case 'last_downloaded':\n orderByClause = 'last_download DESC';\n break;\n default:\n orderByClause = '';\n }\n if (orderByClause) {\n orderByClause = `ORDER BY ${orderByClause}`;\n }\n let limitOffsetClause = '';\n const limitOffsetValues: number[] = [];\n if (limit !== undefined && offset !== undefined) {\n limitOffsetClause = 'LIMIT ? OFFSET ?';\n limitOffsetValues.push(limit, offset);\n }\n else if (limit !== undefined) {\n limitOffsetClause = 'LIMIT ?';\n limitOffsetValues.push(limit);\n }\n const postCountSelect = `\n SELECT\n COUNT(*) AS post_count,\n campaign_id\n FROM content\n WHERE content_type = 'post' GROUP BY campaign_id\n `;\n const productCountSelect = `\n SELECT\n COUNT(*) AS product_count,\n campaign_id\n FROM content\n WHERE content_type = 'product' GROUP BY campaign_id\n `;\n const mediaCountSelect = this.getMediaListSQL({\n select: 'COUNT(content_media.media_id) AS media_count, content_media.campaign_id',\n groupBy: 'content_media.campaign_id'\n });\n try {\n const rows = this.all(\n `\n SELECT\n details,\n IFNULL(post_count, 0) post_count,\n IFNULL(product_count, 0) product_count,\n IFNULL(media_count, 0) media_count,\n COALESCE(post_count, 0) + COALESCE(product_count, 0) content_count\n FROM campaign\n LEFT JOIN (${postCountSelect}) postc ON postc.campaign_id = campaign.campaign_id\n LEFT JOIN (${productCountSelect}) productc ON productc.campaign_id = campaign.campaign_id \n LEFT JOIN (${mediaCountSelect}) mc ON mc.campaign_id = campaign.campaign_id \n ${orderByClause}\n ${limitOffsetClause}\n `,\n [...limitOffsetValues]\n );\n const campaigns = rows.map((row) => ({\n ...JSON.parse(row.details) as Campaign,\n postCount: (row.post_count || 0) as number,\n productCount: (row.product_count || 0) as number,\n mediaCount: (row.media_count || 0) as number\n }));\n const totalResult = this.get(\n `SELECT COUNT(*) AS campaign_count FROM campaign`\n );\n const total = totalResult ? (totalResult.campaign_count as number) : 0;\n return {\n campaigns,\n total\n };\n } catch (error) {\n const _error = Error(`Failed to get campaigns from DB:`, {\n cause: error\n });\n this.log('error', _error);\n throw _error;\n }\n }\n\n #getCampaignWithCounts(params: GetCampaignParams): CampaignWithCounts | null {\n const { id, vanity } = params;\n const joinUser = vanity ? `LEFT JOIN user ON user.user_id = campaign.creator_id` : ''\n const whereClause = vanity ? `WHERE user.vanity = ?` : `WHERE campaign.campaign_id = ?`;\n const whereValues = vanity ? [ vanity ] : [ id ];\n const row = this.get(\n `\n SELECT\n campaign.details,\n IFNULL(media_count, 0) AS media_count,\n IFNULL(post_count, 0) AS post_count,\n IFNULL(product_count, 0) AS product_count\n FROM\n campaign\n ${joinUser}\n LEFT JOIN (SELECT COUNT(content_id) AS post_count, campaign_id FROM content WHERE content_type = 'post' GROUP BY campaign_id) postc ON postc.campaign_id = campaign.campaign_id\n LEFT JOIN (SELECT COUNT(content_id) AS product_count, campaign_id FROM content WHERE content_type = 'product' GROUP BY campaign_id) productc ON productc.campaign_id = campaign.campaign_id\n LEFT JOIN (SELECT COUNT(media_id) AS media_count, campaign_id FROM content_media GROUP BY campaign_id) mc ON mc.campaign_id = campaign.campaign_id\n ${whereClause}\n `,\n [...whereValues]\n );\n return row ? {\n ...JSON.parse(row.details) as Campaign,\n postCount: (row.post_count || 0) as number,\n productCount: (row.product_count || 0) as number,\n mediaCount: (row.media_count || 0) as number\n }\n : null;\n }\n\n checkCampaignExists(id: string) {\n this.log('debug', `Check if campaign #${id} exists in DB`);\n try {\n const result = this.get(\n `SELECT COUNT(*) as count FROM campaign WHERE campaign_id = ?`,\n [id]\n );\n return result.count > 0;\n } catch (error) {\n this.log(\n 'error',\n `Failed to check if campaign #${id} exists in DB:`,\n error\n );\n return false;\n }\n }\n };\n}\n"]}
1
+ {"version":3,"file":"CampaignDBMixin.js","sourceRoot":"","sources":["../../../src/browse/db/CampaignDBMixin.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Reward } from '../../entities/Reward.js';\nimport { type Campaign } from '../../entities/Campaign.js';\nimport { type UserDBConstructor } from './UserDBMixin.js';\nimport { type CampaignList, type CampaignWithCounts, type GetCampaignListParams, type GetCampaignParams } from '../types/Campaign.js';\n\nexport type CampaignDBConstructor = new (\n ...args: any[]\n) => InstanceType<ReturnType<typeof CampaignDBMixin<UserDBConstructor>>>;\n\nconst NULL_CAMPAIGN: Campaign = {\n type: 'campaign',\n id: '-1',\n name: '',\n createdAt: null,\n publishedAt: null,\n avatarImage: {\n type: 'image',\n id: '-1',\n filename: 'avatar',\n createdAt: null,\n mimeType: null,\n downloadURL: null,\n imageType: 'default',\n imageURLs: {\n default: null,\n defaultSmall: null,\n original: null,\n thumbnail: null,\n thumbnailLarge: null,\n thumbnailSmall: null\n },\n thumbnailURL: null\n },\n coverPhoto: {\n type: 'image',\n id: 'campaign:-1:cover',\n filename: 'cover-photo',\n mimeType: null,\n imageType: 'campaignCoverPhoto',\n imageURLs: {\n large: null,\n medium: null,\n small: null,\n xlarge: null,\n xsmall: null\n }\n },\n summary: null,\n url: null,\n currency: null,\n rewards: [],\n creator: null,\n raw: {}\n}\n\nexport function CampaignDBMixin<TBase extends UserDBConstructor>(Base: TBase) {\n return class CampaignDB extends Base {\n saveCampaign(campaign: Campaign | null, downloadDate: Date, overwriteIfExists = true) {\n if (!campaign) {\n campaign = NULL_CAMPAIGN; \n }\n this.log('debug', `Save campaign #${campaign.id} (${campaign.name}) to DB`);\n try {\n const campaignExists = this.checkCampaignExists(campaign.id);\n if (campaignExists && !overwriteIfExists) {\n return;\n }\n\n this.exec('BEGIN TRANSACTION');\n\n // Save creator\n this.saveUser(campaign.creator);\n\n this.saveMedia(campaign.avatarImage);\n this.saveMedia(campaign.coverPhoto);\n\n if (!campaignExists) {\n this.run(\n `\n INSERT INTO campaign (\n campaign_id,\n creator_id,\n campaign_name,\n last_download,\n details\n )\n VALUES (?, ?, ?, ?, ?)\n `,\n [\n campaign.id,\n campaign.creator?.id || '-1',\n campaign.name,\n downloadDate.getTime(),\n JSON.stringify(campaign)\n ]\n );\n } else {\n this.log('debug', `Campaign #${campaign.id} already exists in DB - update record`);\n this.run(`\n UPDATE campaign\n SET\n creator_id = ?,\n campaign_name = ?,\n last_download = ?,\n details = ?\n WHERE campaign_id = ?\n `,\n [\n campaign.creator?.id || '-1',\n campaign.name,\n downloadDate.getTime(),\n JSON.stringify(campaign),\n campaign.id\n ]\n );\n }\n\n // Save rewards\n this.#saveRewards(campaign);\n\n this.exec('COMMIT');\n } catch (error) {\n this.log(\n 'error',\n `Failed to save campaign #${campaign.id} (${campaign.name}) to DB:`,\n error\n );\n this.exec('ROLLBACK');\n }\n }\n\n getCampaign(params: GetCampaignParams)\n {\n const { id, vanity, withCounts = false } = params;\n if (id) {\n this.log('debug', `Get campaign by ID \"${id}\" from DB`);\n }\n else if (vanity) {\n this.log('debug', `Get campaign by vanity \"${vanity}\" from DB`);\n }\n if (!id && !vanity) {\n throw Error('Invalid params: expecting \"id\" or \"vanity\" but got none.')\n }\n if (withCounts) {\n return this.#getCampaignWithCounts(params);\n }\n let result;\n if (id) {\n result = this.get(\n `SELECT details FROM campaign WHERE campaign_id = ?`,\n [params.id]\n );\n }\n else {\n result = this.get(\n `\n SELECT campaign.details\n FROM campaign\n LEFT JOIN user ON user.user_id = campaign.creator_id\n WHERE user.vanity = ?;\n `,\n [params.vanity]\n );\n }\n return result ? JSON.parse(result.details) as Campaign : null;\n }\n\n #saveRewards(campaign: Campaign) {\n if (campaign.id === NULL_CAMPAIGN.id) {\n this.log('warn', 'Skip save rewards to DB because campaign is null');\n return;\n }\n // Clear existing rewards for campaign\n this.log('debug', `Clear existing rewards in DB for campaign #${campaign.id} before saving current ones`);\n this.run(`DELETE FROM reward WHERE campaign_id = ?`, [\n campaign.id\n ]);\n campaign.rewards.forEach((reward) => this.#doSaveReward(campaign, reward));\n }\n\n #doSaveReward(campaign: Campaign, reward: Reward) {\n this.log('debug', `Add reward #${reward.id} (${reward.title}) to DB`);\n try {\n if (reward.image) {\n this.saveMedia(reward.image);\n }\n this.run(`\n INSERT INTO reward (\n reward_id,\n campaign_id,\n title,\n details\n )\n VALUES (?, ?, ?, ?)\n `,\n [\n reward.id,\n campaign.id,\n reward.title,\n JSON.stringify(reward)\n ]);\n }\n catch (error) {\n this.log(\n 'error',\n `Failed to save reward #${reward.id} (${reward.title}) to DB:`,\n error\n );\n throw error;\n }\n }\n\n getCampaignList(params: GetCampaignListParams): CampaignList {\n const { sortBy, limit, offset } = params;\n this.log('debug', 'Get campaigns from DB:', params);\n let orderByClause: string;\n switch (sortBy) {\n case 'a-z':\n orderByClause = 'campaign_name ASC';\n break;\n case 'z-a':\n orderByClause = 'campaign_name DESC';\n break;\n case 'most_content':\n orderByClause = 'content_count DESC';\n break;\n case 'most_media':\n orderByClause = 'media_count DESC';\n break;\n case 'last_downloaded':\n orderByClause = 'last_download DESC';\n break;\n default:\n orderByClause = '';\n }\n if (orderByClause) {\n orderByClause = `ORDER BY ${orderByClause}`;\n }\n let limitOffsetClause = '';\n const limitOffsetValues: number[] = [];\n if (limit !== undefined && offset !== undefined) {\n limitOffsetClause = 'LIMIT ? OFFSET ?';\n limitOffsetValues.push(limit, offset);\n }\n else if (limit !== undefined) {\n limitOffsetClause = 'LIMIT ?';\n limitOffsetValues.push(limit);\n }\n const postCountSelect = `\n SELECT\n COUNT(*) AS post_count,\n campaign_id\n FROM content\n WHERE content_type = 'post' GROUP BY campaign_id\n `;\n const productCountSelect = `\n SELECT\n COUNT(*) AS product_count,\n campaign_id\n FROM content\n WHERE content_type = 'product' GROUP BY campaign_id\n `;\n const mediaCountSelect = this.getMediaListSQL({\n select: 'COUNT(content_media.media_id) AS media_count, content_media.campaign_id',\n groupBy: 'content_media.campaign_id'\n });\n const collectionCountSelect = `\n SELECT\n COUNT(collection_id) AS collection_count,\n campaign_id\n FROM collection GROUP BY campaign_id\n `;\n try {\n const rows = this.all(\n `\n SELECT\n details,\n IFNULL(post_count, 0) post_count,\n IFNULL(product_count, 0) product_count,\n IFNULL(media_count, 0) media_count,\n IFNULL(collection_count, 0) AS collection_count,\n COALESCE(post_count, 0) + COALESCE(product_count, 0) content_count\n FROM campaign\n LEFT JOIN (${postCountSelect}) postc ON postc.campaign_id = campaign.campaign_id\n LEFT JOIN (${productCountSelect}) productc ON productc.campaign_id = campaign.campaign_id \n LEFT JOIN (${mediaCountSelect}) mc ON mc.campaign_id = campaign.campaign_id \n LEFT JOIN (${collectionCountSelect}) cc ON cc.campaign_id = campaign.campaign_id\n ${orderByClause}\n ${limitOffsetClause}\n `,\n [...limitOffsetValues]\n );\n const campaigns = rows.map((row) => ({\n ...JSON.parse(row.details) as Campaign,\n postCount: (row.post_count || 0) as number,\n collectionCount: (row.collection_count || 0) as number,\n productCount: (row.product_count || 0) as number,\n mediaCount: (row.media_count || 0) as number\n }));\n const totalResult = this.get(\n `SELECT COUNT(*) AS campaign_count FROM campaign`\n );\n const total = totalResult ? (totalResult.campaign_count as number) : 0;\n return {\n campaigns,\n total\n };\n } catch (error) {\n const _error = Error(`Failed to get campaigns from DB:`, {\n cause: error\n });\n this.log('error', _error);\n throw _error;\n }\n }\n\n #getCampaignWithCounts(params: GetCampaignParams): CampaignWithCounts | null {\n const { id, vanity } = params;\n const joinUser = vanity ? `LEFT JOIN user ON user.user_id = campaign.creator_id` : ''\n const whereClause = vanity ? `WHERE user.vanity = ?` : `WHERE campaign.campaign_id = ?`;\n const whereValues = vanity ? [ vanity ] : [ id ];\n const row = this.get(\n `\n SELECT\n campaign.details,\n IFNULL(media_count, 0) AS media_count,\n IFNULL(post_count, 0) AS post_count,\n IFNULL(product_count, 0) AS product_count,\n IFNULL(collection_count, 0) AS collection_count\n FROM\n campaign\n ${joinUser}\n LEFT JOIN (SELECT COUNT(content_id) AS post_count, campaign_id FROM content WHERE content_type = 'post' GROUP BY campaign_id) postc ON postc.campaign_id = campaign.campaign_id\n LEFT JOIN (SELECT COUNT(content_id) AS product_count, campaign_id FROM content WHERE content_type = 'product' GROUP BY campaign_id) productc ON productc.campaign_id = campaign.campaign_id\n LEFT JOIN (SELECT COUNT(media_id) AS media_count, campaign_id FROM content_media GROUP BY campaign_id) mc ON mc.campaign_id = campaign.campaign_id\n LEFT JOIN (SELECT COUNT(collection_id) AS collection_count, campaign_id FROM collection GROUP BY campaign_id) collectionc ON collectionc.campaign_id = campaign.campaign_id\n ${whereClause}\n `,\n [...whereValues]\n );\n return row ? {\n ...JSON.parse(row.details) as Campaign,\n postCount: (row.post_count || 0) as number,\n collectionCount: (row.collection_count || 0) as number,\n productCount: (row.product_count || 0) as number,\n mediaCount: (row.media_count || 0) as number\n }\n : null;\n }\n\n checkCampaignExists(id: string) {\n this.log('debug', `Check if campaign #${id} exists in DB`);\n try {\n const result = this.get(\n `SELECT COUNT(*) as count FROM campaign WHERE campaign_id = ?`,\n [id]\n );\n return result.count > 0;\n } catch (error) {\n this.log(\n 'error',\n `Failed to check if campaign #${id} exists in DB:`,\n error\n );\n return false;\n }\n }\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { type Database } from "better-sqlite3";
2
+ export declare function initDBCollectionFTS(db: Database): void;
@@ -0,0 +1,68 @@
1
+ const COLLECTION_FTS_SOURCE_DELETE_SQL = `DELETE FROM collection_fts_source WHERE collection_id = old.collection_id;`;
2
+ const COLLECTION_FTS_SOURCE_INSERT_SQL = `
3
+ INSERT INTO collection_fts_source(collection_id, title, body)
4
+ VALUES(
5
+ new.collection_id,
6
+ json_extract(new.details, '$.title'),
7
+ json_extract(new.details, '$.description')
8
+ );
9
+ `;
10
+ const COLLECTION_FTS_DELETE_SQL = `DELETE FROM collection_fts WHERE rowid = old.fts_rowid;`;
11
+ const COLLECTION_FTS_INSERT_SQL = `
12
+ INSERT INTO collection_fts(rowid, title, body)
13
+ VALUES (
14
+ new.fts_rowid,
15
+ new.title,
16
+ new.body
17
+ );
18
+ `;
19
+ const COLLECTION_FTS_INIT = `
20
+ CREATE TABLE IF NOT EXISTS "collection_fts_source" (
21
+ "fts_rowid" INTEGER,
22
+ "collection_id" TEXT NOT NULL,
23
+ "title" TEXT,
24
+ "body" TEXT,
25
+ PRIMARY KEY("fts_rowid"),
26
+ FOREIGN KEY("collection_id") REFERENCES "collection"("collection_id")
27
+ );
28
+
29
+ CREATE VIRTUAL TABLE IF NOT EXISTS collection_fts USING fts5(
30
+ title,
31
+ body,
32
+ content = 'collection_fts_source',
33
+ content_rowid = 'fts_rowid'
34
+ );
35
+
36
+ CREATE TRIGGER IF NOT EXISTS collection_ai AFTER INSERT ON collection BEGIN
37
+ ${COLLECTION_FTS_SOURCE_INSERT_SQL}
38
+ END;
39
+
40
+ CREATE TRIGGER IF NOT EXISTS collection_au AFTER UPDATE ON collection BEGIN
41
+ ${COLLECTION_FTS_SOURCE_DELETE_SQL}
42
+ ${COLLECTION_FTS_SOURCE_INSERT_SQL}
43
+ END;
44
+
45
+ CREATE TRIGGER IF NOT EXISTS collection_ad AFTER DELETE ON collection BEGIN
46
+ ${COLLECTION_FTS_SOURCE_DELETE_SQL}
47
+ END;
48
+
49
+ CREATE TRIGGER IF NOT EXISTS collection_fts_source_ai AFTER INSERT ON collection_fts_source BEGIN
50
+ ${COLLECTION_FTS_INSERT_SQL}
51
+ END;
52
+
53
+ CREATE TRIGGER IF NOT EXISTS collection_fts_source_bu BEFORE UPDATE ON collection_fts_source BEGIN
54
+ ${COLLECTION_FTS_DELETE_SQL}
55
+ END;
56
+
57
+ CREATE TRIGGER IF NOT EXISTS collection_fts_source_au AFTER UPDATE ON collection_fts_source BEGIN
58
+ ${COLLECTION_FTS_INSERT_SQL}
59
+ END;
60
+
61
+ CREATE TRIGGER IF NOT EXISTS collection_fts_source_bd BEFORE DELETE ON collection_fts_source BEGIN
62
+ ${COLLECTION_FTS_DELETE_SQL}
63
+ END;
64
+ `;
65
+ export function initDBCollectionFTS(db) {
66
+ db.exec(COLLECTION_FTS_INIT);
67
+ }
68
+ //# sourceMappingURL=CollectionFTS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionFTS.js","sourceRoot":"","sources":["../../../src/browse/db/CollectionFTS.ts"],"names":[],"mappings":"AAEA,MAAM,gCAAgC,GAAG,4EAA4E,CAAC;AACtH,MAAM,gCAAgC,GAAG;;;;;;;CAOxC,CAAC;AACF,MAAM,yBAAyB,GAAG,yDAAyD,CAAC;AAC5F,MAAM,yBAAyB,GAAG;;;;;;;CAOjC,CAAC;AACF,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;MAkBtB,gCAAgC;;;;MAIhC,gCAAgC;MAChC,gCAAgC;;;;MAIhC,gCAAgC;;;;MAIhC,yBAAyB;;;;MAIzB,yBAAyB;;;;MAIzB,yBAAyB;;;;MAIzB,yBAAyB;;CAE9B,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,EAAY;IAC9C,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["import { type Database } from \"better-sqlite3\";\n\nconst COLLECTION_FTS_SOURCE_DELETE_SQL = `DELETE FROM collection_fts_source WHERE collection_id = old.collection_id;`;\nconst COLLECTION_FTS_SOURCE_INSERT_SQL = `\n INSERT INTO collection_fts_source(collection_id, title, body)\n VALUES(\n new.collection_id,\n json_extract(new.details, '$.title'),\n json_extract(new.details, '$.description')\n );\n`;\nconst COLLECTION_FTS_DELETE_SQL = `DELETE FROM collection_fts WHERE rowid = old.fts_rowid;`;\nconst COLLECTION_FTS_INSERT_SQL = `\n INSERT INTO collection_fts(rowid, title, body)\n VALUES (\n new.fts_rowid,\n new.title,\n new.body\n );\n`;\nconst COLLECTION_FTS_INIT = `\n CREATE TABLE IF NOT EXISTS \"collection_fts_source\" (\n \"fts_rowid\" INTEGER,\n \"collection_id\" TEXT NOT NULL,\n \"title\"\tTEXT,\n \"body\" TEXT,\n PRIMARY KEY(\"fts_rowid\"),\n FOREIGN KEY(\"collection_id\") REFERENCES \"collection\"(\"collection_id\")\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS collection_fts USING fts5(\n title,\n body,\n content = 'collection_fts_source',\n content_rowid = 'fts_rowid'\n );\n\n CREATE TRIGGER IF NOT EXISTS collection_ai AFTER INSERT ON collection BEGIN\n ${COLLECTION_FTS_SOURCE_INSERT_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_au AFTER UPDATE ON collection BEGIN\n ${COLLECTION_FTS_SOURCE_DELETE_SQL}\n ${COLLECTION_FTS_SOURCE_INSERT_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_ad AFTER DELETE ON collection BEGIN\n ${COLLECTION_FTS_SOURCE_DELETE_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_fts_source_ai AFTER INSERT ON collection_fts_source BEGIN\n ${COLLECTION_FTS_INSERT_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_fts_source_bu BEFORE UPDATE ON collection_fts_source BEGIN\n ${COLLECTION_FTS_DELETE_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_fts_source_au AFTER UPDATE ON collection_fts_source BEGIN\n ${COLLECTION_FTS_INSERT_SQL}\n END;\n\n CREATE TRIGGER IF NOT EXISTS collection_fts_source_bd BEFORE DELETE ON collection_fts_source BEGIN\n ${COLLECTION_FTS_DELETE_SQL}\n END;\n`;\n\nexport function initDBCollectionFTS(db: Database) {\n db.exec(COLLECTION_FTS_INIT);\n}"]}