podverse-parser 5.1.14-alpha.0 → 5.1.16-alpha.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.
@@ -0,0 +1,7 @@
1
+ import { Channel } from 'podverse-orm';
2
+ import { HandleParsedItemsResult } from '@parser/lib/rss/item/item';
3
+ /**
4
+ * Handles sending push notifications for new items parsed from RSS feeds
5
+ */
6
+ export declare function handleNewItemNotifications(channel: Channel, parsedItemsResult: HandleParsedItemsResult): Promise<void>;
7
+ //# sourceMappingURL=handleNewItemNotifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleNewItemNotifications.d.ts","sourceRoot":"","sources":["../../../src/lib/notifications/handleNewItemNotifications.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAA6B,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAuCpE;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,uBAAuB,GACzC,OAAO,CAAC,IAAI,CAAC,CA+Ef"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.handleNewItemNotifications = handleNewItemNotifications;
13
+ const podverse_helpers_1 = require("podverse-helpers");
14
+ const podverse_orm_1 = require("podverse-orm");
15
+ const loggerService_1 = require("@parser/factories/loggerService");
16
+ const sharedNotificationHelpers_1 = require("./sharedNotificationHelpers");
17
+ /**
18
+ * Determines the NotificationMessageType based on the channel's medium_id
19
+ */
20
+ function getMessageTypeFromMedium(medium_id) {
21
+ switch (medium_id) {
22
+ case podverse_helpers_1.MediumEnum.Podcast:
23
+ return 'new-episode';
24
+ case podverse_helpers_1.MediumEnum.PodcastL:
25
+ return 'new-episode';
26
+ case podverse_helpers_1.MediumEnum.PublisherPodcast:
27
+ return 'new-podcast';
28
+ case podverse_helpers_1.MediumEnum.Video:
29
+ return 'new-video';
30
+ case podverse_helpers_1.MediumEnum.VideoL:
31
+ return 'new-video';
32
+ case podverse_helpers_1.MediumEnum.PublisherVideo:
33
+ return 'new-video-channel';
34
+ case podverse_helpers_1.MediumEnum.Music:
35
+ return 'new-track';
36
+ case podverse_helpers_1.MediumEnum.MusicL:
37
+ return 'new-track';
38
+ case podverse_helpers_1.MediumEnum.PublisherMusic:
39
+ return 'new-album';
40
+ default:
41
+ return 'new';
42
+ }
43
+ }
44
+ /**
45
+ * Handles sending push notifications for new items parsed from RSS feeds
46
+ */
47
+ function handleNewItemNotifications(channel, parsedItemsResult) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ try {
50
+ const { newItemGuids, newItemGuidEnclosureUrls } = parsedItemsResult;
51
+ // Early return if no new items
52
+ if (newItemGuids.length === 0 && newItemGuidEnclosureUrls.length === 0) {
53
+ return;
54
+ }
55
+ // Get devices for accounts that have new-item notifications enabled
56
+ const devicesResult = yield (0, sharedNotificationHelpers_1.getDevicesForNotificationType)(channel.id_text, podverse_helpers_1.AccountNotificationTypeEnum.NewItem);
57
+ if (!devicesResult) {
58
+ return;
59
+ }
60
+ const { devices: allDevices } = devicesResult;
61
+ // Get the items to send notifications for using batch queries
62
+ const itemService = new podverse_orm_1.ItemService();
63
+ const items = [];
64
+ // Get items by guids in batch
65
+ if (newItemGuids.length > 0) {
66
+ const itemsByGuid = yield itemService.getManyByGuid(channel, newItemGuids, {
67
+ relations: { item_images: true }
68
+ });
69
+ items.push(...itemsByGuid);
70
+ }
71
+ // Get items by guid_enclosure_urls in batch
72
+ if (newItemGuidEnclosureUrls.length > 0) {
73
+ const itemsByEnclosureUrl = yield itemService.getManyByGuidEnclosureUrl(channel, newItemGuidEnclosureUrls, {
74
+ relations: { item_images: true }
75
+ });
76
+ items.push(...itemsByEnclosureUrl);
77
+ }
78
+ // Early return if no items found
79
+ if (items.length === 0) {
80
+ return;
81
+ }
82
+ // Sort items by pub_date descending and limit to 3 most recent
83
+ const sortedItems = [...items]
84
+ .sort((a, b) => {
85
+ const dateA = a.pub_date ? new Date(a.pub_date).getTime() : 0;
86
+ const dateB = b.pub_date ? new Date(b.pub_date).getTime() : 0;
87
+ return dateB - dateA;
88
+ })
89
+ .slice(0, 3);
90
+ // Load channel images if not already loaded
91
+ const channelImages = yield (0, sharedNotificationHelpers_1.loadChannelImages)(channel);
92
+ // Determine the message type based on channel medium
93
+ const messageType = getMessageTypeFromMedium(channel.medium_id);
94
+ // Prepare notification data for each item (limited to 3 most recent)
95
+ const itemNotifications = sortedItems.map(item => ({
96
+ itemTitle: item.title || '',
97
+ channelTitle: channel.title || '',
98
+ imageUrl: (0, sharedNotificationHelpers_1.getBestImageUrl)(item, channelImages),
99
+ itemIdText: item.id_text,
100
+ channelIdText: channel.id_text,
101
+ messageType
102
+ }));
103
+ // Group devices by locale and platform
104
+ const groupedDevices = (0, sharedNotificationHelpers_1.groupDevicesByLocaleAndPlatform)(allDevices);
105
+ // Send notifications
106
+ yield (0, sharedNotificationHelpers_1.sendItemNotifications)(itemNotifications, groupedDevices);
107
+ }
108
+ catch (error) {
109
+ loggerService_1.loggerService.logError('handleNewItemNotifications', error);
110
+ }
111
+ });
112
+ }
@@ -0,0 +1,9 @@
1
+ import { Channel } from 'podverse-orm';
2
+ import { HandleParsedLiveItemsResult } from '@parser/lib/rss/liveItem/liveItem';
3
+ /**
4
+ * Handles sending push notifications for live items
5
+ * - "livestream-scheduled" notifications for pending live items
6
+ * - "livestream-started" notifications for live items that have started
7
+ */
8
+ export declare function handleNewLiveItemNotifications(channel: Channel, parsedLiveItemsResult: HandleParsedLiveItemsResult): Promise<void>;
9
+ //# sourceMappingURL=handleNewLiveItemNotifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleNewLiveItemNotifications.d.ts","sourceRoot":"","sources":["../../../src/lib/notifications/handleNewLiveItemNotifications.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAA6B,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAWhF;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,OAAO,EAChB,qBAAqB,EAAE,2BAA2B,GACjD,OAAO,CAAC,IAAI,CAAC,CAoCf"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.handleNewLiveItemNotifications = handleNewLiveItemNotifications;
13
+ const podverse_helpers_1 = require("podverse-helpers");
14
+ const podverse_orm_1 = require("podverse-orm");
15
+ const loggerService_1 = require("@parser/factories/loggerService");
16
+ const sharedNotificationHelpers_1 = require("./sharedNotificationHelpers");
17
+ /**
18
+ * Handles sending push notifications for live items
19
+ * - "livestream-scheduled" notifications for pending live items
20
+ * - "livestream-started" notifications for live items that have started
21
+ */
22
+ function handleNewLiveItemNotifications(channel, parsedLiveItemsResult) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ try {
25
+ const { pendingItemGuids, liveItemGuids } = parsedLiveItemsResult;
26
+ // Early return if no live items to notify about
27
+ if (pendingItemGuids.length === 0 && liveItemGuids.length === 0) {
28
+ return;
29
+ }
30
+ // Load channel images once for all notifications
31
+ const channelImages = yield (0, sharedNotificationHelpers_1.loadChannelImages)(channel);
32
+ // Handle pending (scheduled) notifications
33
+ if (pendingItemGuids.length > 0) {
34
+ yield sendLiveItemNotificationsForStatus(channel, pendingItemGuids, channelImages, 'livestream-scheduled', podverse_helpers_1.AccountNotificationTypeEnum.LivestreamScheduled);
35
+ }
36
+ // Handle live (started) notifications
37
+ if (liveItemGuids.length > 0) {
38
+ yield sendLiveItemNotificationsForStatus(channel, liveItemGuids, channelImages, 'livestream-started', podverse_helpers_1.AccountNotificationTypeEnum.LivestreamStarting);
39
+ }
40
+ }
41
+ catch (error) {
42
+ loggerService_1.loggerService.logError('handleNewLiveItemNotifications', error);
43
+ }
44
+ });
45
+ }
46
+ /**
47
+ * Sends notifications for live items with a specific status
48
+ */
49
+ function sendLiveItemNotificationsForStatus(channel, itemGuids, channelImages, messageType, notificationType) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ // Get devices for accounts that have this notification type enabled
52
+ const devicesResult = yield (0, sharedNotificationHelpers_1.getDevicesForNotificationType)(channel.id_text, notificationType);
53
+ if (!devicesResult) {
54
+ return;
55
+ }
56
+ const { devices: allDevices } = devicesResult;
57
+ // Get the items to send notifications for using batch queries
58
+ const itemService = new podverse_orm_1.ItemService();
59
+ const items = yield itemService.getManyByGuid(channel, itemGuids, {
60
+ relations: { item_images: true, live_item: true }
61
+ });
62
+ // Early return if no items found
63
+ if (items.length === 0) {
64
+ return;
65
+ }
66
+ // Sort items by start_time (for live items) or pub_date descending and limit to 3 most recent
67
+ const sortedItems = [...items]
68
+ .sort((a, b) => {
69
+ var _a, _b;
70
+ // Use live_item start_time if available, otherwise fall back to pub_date
71
+ const dateA = ((_a = a.live_item) === null || _a === void 0 ? void 0 : _a.start_time)
72
+ ? new Date(a.live_item.start_time).getTime()
73
+ : (a.pub_date ? new Date(a.pub_date).getTime() : 0);
74
+ const dateB = ((_b = b.live_item) === null || _b === void 0 ? void 0 : _b.start_time)
75
+ ? new Date(b.live_item.start_time).getTime()
76
+ : (b.pub_date ? new Date(b.pub_date).getTime() : 0);
77
+ return dateB - dateA;
78
+ })
79
+ .slice(0, 3);
80
+ // Prepare notification data for each item (limited to 3 most recent)
81
+ const itemNotifications = sortedItems.map(item => ({
82
+ itemTitle: item.title || '',
83
+ channelTitle: channel.title || '',
84
+ imageUrl: (0, sharedNotificationHelpers_1.getBestImageUrl)(item, channelImages),
85
+ itemIdText: item.id_text,
86
+ channelIdText: channel.id_text,
87
+ messageType
88
+ }));
89
+ // Group devices by locale and platform
90
+ const groupedDevices = (0, sharedNotificationHelpers_1.groupDevicesByLocaleAndPlatform)(allDevices);
91
+ // Send notifications
92
+ yield (0, sharedNotificationHelpers_1.sendItemNotifications)(itemNotifications, groupedDevices);
93
+ });
94
+ }
@@ -0,0 +1,54 @@
1
+ import { AccountFCMDevicePlatformEnum, AccountNotificationTypeEnum } from 'podverse-helpers';
2
+ import { Channel, ChannelImage, Item } from 'podverse-orm';
3
+ import { NotificationMessageType, NotificationPlatform } from 'podverse-external-services';
4
+ export type DeviceWithLocale = {
5
+ fcm_token: string;
6
+ platform: NotificationPlatform;
7
+ locale: string;
8
+ account_id: number;
9
+ };
10
+ export type ItemNotificationData = {
11
+ itemTitle: string;
12
+ channelTitle: string;
13
+ imageUrl: string | null;
14
+ itemIdText: string;
15
+ channelIdText: string;
16
+ messageType: NotificationMessageType;
17
+ };
18
+ /**
19
+ * Selects the best image from a list based on notification requirements.
20
+ * Prefers images above minimum size, closest to ideal size.
21
+ * Falls back to largest available if none meet minimum.
22
+ */
23
+ export declare function selectBestImage<T extends {
24
+ url: string;
25
+ image_width_size?: number | null;
26
+ }>(images: T[]): string | null;
27
+ /**
28
+ * Gets the best available image URL from item images or channel images
29
+ */
30
+ export declare function getBestImageUrl(item: Item, channelImages: ChannelImage[]): string | null;
31
+ /**
32
+ * Converts AccountFCMDevicePlatformEnum to NotificationPlatform
33
+ */
34
+ export declare function convertPlatform(platform: AccountFCMDevicePlatformEnum): NotificationPlatform;
35
+ /**
36
+ * Groups devices by locale and platform for batch notification sending
37
+ */
38
+ export declare function groupDevicesByLocaleAndPlatform(devices: DeviceWithLocale[]): Map<string, Map<NotificationPlatform, string[]>>;
39
+ /**
40
+ * Loads channel images if not already present on the channel object
41
+ */
42
+ export declare function loadChannelImages(channel: Channel): Promise<ChannelImage[]>;
43
+ /**
44
+ * Gets devices for accounts that have a specific notification type enabled for a channel
45
+ */
46
+ export declare function getDevicesForNotificationType(channelIdText: string, notificationType: AccountNotificationTypeEnum): Promise<{
47
+ devices: DeviceWithLocale[];
48
+ accountLocaleMap: Map<number, string>;
49
+ } | null>;
50
+ /**
51
+ * Sends notifications for items to grouped devices
52
+ */
53
+ export declare function sendItemNotifications(itemNotifications: ItemNotificationData[], groupedDevices: Map<string, Map<NotificationPlatform, string[]>>): Promise<void>;
54
+ //# sourceMappingURL=sharedNotificationHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedNotificationHelpers.d.ts","sourceRoot":"","sources":["../../../src/lib/notifications/sharedNotificationHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAIL,OAAO,EACP,YAAY,EAEZ,IAAI,EACL,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,uBAAuB,EAA4B,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGrH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,uBAAuB,CAAC;CACtC,CAAC;AAOF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACzF,MAAM,EAAE,CAAC,EAAE,GACV,MAAM,GAAG,IAAI,CA8Bf;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,MAAM,GAAG,IAAI,CAexF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,4BAA4B,GAAG,oBAAoB,CAY5F;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,oBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC,CAgB7H;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAUjF;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,2BAA2B,GAC5C,OAAO,CAAC;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,CA0DxF;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,iBAAiB,EAAE,oBAAoB,EAAE,EACzC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,oBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC,CAmCf"}
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.selectBestImage = selectBestImage;
13
+ exports.getBestImageUrl = getBestImageUrl;
14
+ exports.convertPlatform = convertPlatform;
15
+ exports.groupDevicesByLocaleAndPlatform = groupDevicesByLocaleAndPlatform;
16
+ exports.loadChannelImages = loadChannelImages;
17
+ exports.getDevicesForNotificationType = getDevicesForNotificationType;
18
+ exports.sendItemNotifications = sendItemNotifications;
19
+ const podverse_helpers_1 = require("podverse-helpers");
20
+ const podverse_orm_1 = require("podverse-orm");
21
+ const podverse_external_services_1 = require("podverse-external-services");
22
+ const loggerService_1 = require("@parser/factories/loggerService");
23
+ // Minimum acceptable image size for notifications (in pixels)
24
+ const NOTIFICATION_IMAGE_MIN_SIZE = 200;
25
+ // Ideal image size for notifications - not too large to waste bandwidth
26
+ const NOTIFICATION_IMAGE_IDEAL_SIZE = 512;
27
+ /**
28
+ * Selects the best image from a list based on notification requirements.
29
+ * Prefers images above minimum size, closest to ideal size.
30
+ * Falls back to largest available if none meet minimum.
31
+ */
32
+ function selectBestImage(images) {
33
+ if (!images || images.length === 0) {
34
+ return null;
35
+ }
36
+ // Filter images that meet the minimum size requirement
37
+ const adequateImages = images.filter(img => (img.image_width_size || 0) >= NOTIFICATION_IMAGE_MIN_SIZE);
38
+ if (adequateImages.length > 0) {
39
+ // From adequate images, find the one closest to ideal size
40
+ // Prefer slightly larger over slightly smaller
41
+ const sortedByIdeal = [...adequateImages].sort((a, b) => {
42
+ const diffA = Math.abs((a.image_width_size || 0) - NOTIFICATION_IMAGE_IDEAL_SIZE);
43
+ const diffB = Math.abs((b.image_width_size || 0) - NOTIFICATION_IMAGE_IDEAL_SIZE);
44
+ if (diffA === diffB) {
45
+ // If equal distance from ideal, prefer the larger one
46
+ return (b.image_width_size || 0) - (a.image_width_size || 0);
47
+ }
48
+ return diffA - diffB;
49
+ });
50
+ return sortedByIdeal[0].url;
51
+ }
52
+ // No images meet minimum size - fall back to largest available
53
+ const sortedBySize = [...images].sort((a, b) => (b.image_width_size || 0) - (a.image_width_size || 0));
54
+ return sortedBySize[0].url;
55
+ }
56
+ /**
57
+ * Gets the best available image URL from item images or channel images
58
+ */
59
+ function getBestImageUrl(item, channelImages) {
60
+ // Try item images first
61
+ if (item.item_images && item.item_images.length > 0) {
62
+ const itemImageUrl = selectBestImage(item.item_images);
63
+ if (itemImageUrl) {
64
+ return itemImageUrl;
65
+ }
66
+ }
67
+ // Fall back to channel images
68
+ if (channelImages && channelImages.length > 0) {
69
+ return selectBestImage(channelImages);
70
+ }
71
+ return null;
72
+ }
73
+ /**
74
+ * Converts AccountFCMDevicePlatformEnum to NotificationPlatform
75
+ */
76
+ function convertPlatform(platform) {
77
+ switch (platform) {
78
+ case podverse_helpers_1.AccountFCMDevicePlatformEnum.Web:
79
+ return 'web';
80
+ case podverse_helpers_1.AccountFCMDevicePlatformEnum.Android:
81
+ return 'android';
82
+ case podverse_helpers_1.AccountFCMDevicePlatformEnum.iOS:
83
+ return 'ios';
84
+ case podverse_helpers_1.AccountFCMDevicePlatformEnum.Generic:
85
+ default:
86
+ return 'generic';
87
+ }
88
+ }
89
+ /**
90
+ * Groups devices by locale and platform for batch notification sending
91
+ */
92
+ function groupDevicesByLocaleAndPlatform(devices) {
93
+ const localeMap = new Map();
94
+ for (const device of devices) {
95
+ if (!localeMap.has(device.locale)) {
96
+ localeMap.set(device.locale, new Map());
97
+ }
98
+ const platformMap = localeMap.get(device.locale);
99
+ if (!platformMap.has(device.platform)) {
100
+ platformMap.set(device.platform, []);
101
+ }
102
+ platformMap.get(device.platform).push(device.fcm_token);
103
+ }
104
+ return localeMap;
105
+ }
106
+ /**
107
+ * Loads channel images if not already present on the channel object
108
+ */
109
+ function loadChannelImages(channel) {
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ if (channel.channel_images) {
112
+ return channel.channel_images;
113
+ }
114
+ const channelService = new podverse_orm_1.ChannelService();
115
+ const channelWithImages = yield channelService.getByIdText(channel.id_text, {
116
+ channel_images: true
117
+ });
118
+ return (channelWithImages === null || channelWithImages === void 0 ? void 0 : channelWithImages.channel_images) || [];
119
+ });
120
+ }
121
+ /**
122
+ * Gets devices for accounts that have a specific notification type enabled for a channel
123
+ */
124
+ function getDevicesForNotificationType(channelIdText, notificationType) {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ var _a, _b, _c, _d;
127
+ // Get all account notification channels for this channel with their types
128
+ const accountNotificationChannelService = new podverse_orm_1.AccountNotificationChannelService();
129
+ const notificationChannels = yield accountNotificationChannelService.getAllByChannelIdText(channelIdText, {
130
+ relations: {
131
+ account_notification_channel_types: true,
132
+ account: {
133
+ account_settings: {
134
+ account_settings_locale: true
135
+ }
136
+ }
137
+ }
138
+ });
139
+ // Filter to only accounts that have the specified notification type enabled
140
+ const accountIdsWithTypeEnabled = [];
141
+ const accountLocaleMap = new Map();
142
+ for (const notificationChannel of notificationChannels) {
143
+ const hasType = (_a = notificationChannel.account_notification_channel_types) === null || _a === void 0 ? void 0 : _a.some((type) => type.type === notificationType);
144
+ if (hasType) {
145
+ accountIdsWithTypeEnabled.push(notificationChannel.account_id);
146
+ // Store the locale for each account
147
+ const locale = ((_d = (_c = (_b = notificationChannel.account) === null || _b === void 0 ? void 0 : _b.account_settings) === null || _c === void 0 ? void 0 : _c.account_settings_locale) === null || _d === void 0 ? void 0 : _d.locale) || 'en-US';
148
+ accountLocaleMap.set(notificationChannel.account_id, locale);
149
+ }
150
+ }
151
+ // Early return if no accounts have this notification type enabled
152
+ if (accountIdsWithTypeEnabled.length === 0) {
153
+ return null;
154
+ }
155
+ // Get all FCM devices for the filtered account IDs in a single batch query
156
+ const accountFCMDeviceService = new podverse_orm_1.AccountFCMDeviceService();
157
+ const deviceResults = yield accountFCMDeviceService.getAllForAccountIds(accountIdsWithTypeEnabled);
158
+ // Early return if no devices to send to
159
+ if (deviceResults.length === 0) {
160
+ return null;
161
+ }
162
+ // Map devices to DeviceWithLocale format
163
+ const devices = deviceResults.map(device => ({
164
+ fcm_token: device.fcm_token,
165
+ platform: convertPlatform(device.platform),
166
+ locale: device.locale || accountLocaleMap.get(device.account_id) || 'en-US',
167
+ account_id: device.account_id
168
+ }));
169
+ return { devices, accountLocaleMap };
170
+ });
171
+ }
172
+ /**
173
+ * Sends notifications for items to grouped devices
174
+ */
175
+ function sendItemNotifications(itemNotifications, groupedDevices) {
176
+ return __awaiter(this, void 0, void 0, function* () {
177
+ for (const itemNotification of itemNotifications) {
178
+ const messageText = `${itemNotification.channelTitle} - ${itemNotification.itemTitle}`;
179
+ for (const [locale, platformMap] of groupedDevices) {
180
+ for (const [platform, tokens] of platformMap) {
181
+ try {
182
+ yield (0, podverse_external_services_1.notificationOrchestrator)({
183
+ service: 'firebase',
184
+ tokens,
185
+ messageText,
186
+ messageType: itemNotification.messageType,
187
+ locale,
188
+ platform,
189
+ icon: itemNotification.imageUrl || undefined,
190
+ linkIdText: itemNotification.itemIdText,
191
+ data: {
192
+ itemIdText: itemNotification.itemIdText,
193
+ channelIdText: itemNotification.channelIdText,
194
+ type: itemNotification.messageType
195
+ }
196
+ });
197
+ loggerService_1.loggerService.info(`Sent ${itemNotification.messageType} notification to ${tokens.length} ${platform} devices (${locale}) for item: ${itemNotification.itemIdText}`);
198
+ }
199
+ catch (error) {
200
+ loggerService_1.loggerService.logError(`Failed to send notification for item ${itemNotification.itemIdText} to ${platform} devices (${locale})`, error);
201
+ }
202
+ }
203
+ }
204
+ }
205
+ });
206
+ }
@@ -1,7 +1,10 @@
1
1
  import { Phase4PodcastLiveItem } from "podverse-partytime/dist/parser/phase/phase-4";
2
2
  import { Channel, ChannelSeasonIndex } from "podverse-orm";
3
3
  export type HandleParsedLiveItemsResult = {
4
- newItemGuids: string[];
4
+ /** GUIDs of live items that are new or changed to "pending" status */
5
+ pendingItemGuids: string[];
6
+ /** GUIDs of live items that are new or changed to "live" status */
7
+ liveItemGuids: string[];
5
8
  };
6
9
  export declare const handleParsedLiveItems: (parsedLiveItems: Phase4PodcastLiveItem[], channel: Channel, channelSeasonIndex: ChannelSeasonIndex) => Promise<HandleParsedLiveItemsResult>;
7
10
  //# sourceMappingURL=liveItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"liveItem.d.ts","sourceRoot":"","sources":["../../../../src/lib/rss/liveItem/liveItem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,OAAO,EAA0B,OAAO,EAAE,kBAAkB,EAA0F,MAAM,cAAc,CAAC;AAO3K,MAAM,MAAM,2BAA2B,GAAG;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AA2DF,eAAO,MAAM,qBAAqB,GAChC,iBAAiB,qBAAqB,EAAE,EACxC,SAAS,OAAO,EAChB,oBAAoB,kBAAkB,KACrC,OAAO,CAAC,2BAA2B,CAsCrC,CAAC"}
1
+ {"version":3,"file":"liveItem.d.ts","sourceRoot":"","sources":["../../../../src/lib/rss/liveItem/liveItem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AAErF,OAAO,EAA0B,OAAO,EAAE,kBAAkB,EAA0F,MAAM,cAAc,CAAC;AAO3K,MAAM,MAAM,2BAA2B,GAAG;IACxC,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mEAAmE;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AA0EF,eAAO,MAAM,qBAAqB,GAChC,iBAAiB,qBAAqB,EAAE,EACxC,SAAS,OAAO,EAChB,oBAAoB,kBAAkB,KACrC,OAAO,CAAC,2BAA2B,CAwCrC,CAAC"}
@@ -17,7 +17,7 @@ const item_1 = require("@parser/lib/rss/item/item");
17
17
  const itemFlagStatus_1 = require("podverse-orm/dist/entities/item/itemFlagStatus");
18
18
  const timerManager_1 = require("@parser/factories/timerManager");
19
19
  const loggerService_1 = require("@parser/factories/loggerService");
20
- const processLiveItemBatch = (liveItemObjDtosBatch, channel, channelSeasonIndex, existingLiveItemMap, updatedLiveItemIds, newItemGuids,
20
+ const processLiveItemBatch = (liveItemObjDtosBatch, channel, channelSeasonIndex, existingLiveItemMap, updatedLiveItemIds, pendingItemGuids, liveItemGuids,
21
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
22
  transactionalEntityManager,
23
23
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -34,11 +34,27 @@ timerAccumulator, liveItemService) => __awaiter(void 0, void 0, void 0, function
34
34
  });
35
35
  updatedLiveItemIds.push(item.id);
36
36
  const existingLiveItem = existingLiveItemMap.get(itemDto.guid);
37
- const itemStatusEnum = (0, podverse_orm_1.getLiveItemStatusEnumValue)(itemDto.status);
38
- if (!existingLiveItem ||
39
- (existingLiveItem.live_item_status.id !== podverse_orm_1.LiveItemStatusEnum.Ended && itemStatusEnum === podverse_orm_1.LiveItemStatusEnum.Ended)) {
40
- newItemGuids.push(itemDto.guid);
37
+ const newStatusEnum = (0, podverse_orm_1.getLiveItemStatusEnumValue)(itemDto.status);
38
+ // Determine if we should send a notification based on status changes
39
+ // Send notifications when:
40
+ // 1. New live item with pending or live status
41
+ // 2. Existing live item that changed to pending or live status
42
+ const isNewLiveItem = !existingLiveItem;
43
+ const previousStatus = existingLiveItem === null || existingLiveItem === void 0 ? void 0 : existingLiveItem.live_item_status_id;
44
+ const statusChanged = previousStatus !== newStatusEnum;
45
+ if (newStatusEnum === podverse_orm_1.LiveItemStatusEnum.Pending) {
46
+ // Send pending notification if new or status changed to pending
47
+ if (isNewLiveItem || statusChanged) {
48
+ pendingItemGuids.push(itemDto.guid);
49
+ }
41
50
  }
51
+ else if (newStatusEnum === podverse_orm_1.LiveItemStatusEnum.Live) {
52
+ // Send live notification if new or status changed to live
53
+ if (isNewLiveItem || statusChanged) {
54
+ liveItemGuids.push(itemDto.guid);
55
+ }
56
+ }
57
+ // No notification for "ended" status
42
58
  const liveItemDto = liveItemObjDto.liveItem;
43
59
  yield liveItemService.update(item, liveItemDto);
44
60
  }
@@ -57,13 +73,14 @@ const handleParsedLiveItems = (parsedLiveItems, channel, channelSeasonIndex) =>
57
73
  const existingLiveItemMap = new Map(existingLiveItems.map(live_item => [live_item.item.guid, live_item]));
58
74
  const existingLiveItemItemIds = existingLiveItems.map(live_item => live_item.item.id);
59
75
  const updatedLiveItemItemIds = [];
60
- const newItemGuids = [];
76
+ const pendingItemGuids = [];
77
+ const liveItemGuids = [];
61
78
  const liveItemObjDtos = (0, liveItem_1.compatLiveItemsDtos)(parsedLiveItems);
62
79
  const timerAccumulator = (0, item_1.createItemTimerAccumulator)();
63
80
  const liveItemObjDtosBatchs = (0, podverse_helpers_1.chunkArray)(liveItemObjDtos, 50);
64
81
  for (const liveItemObjDtosBatch of liveItemObjDtosBatchs) {
65
82
  yield podverse_orm_1.AppDataSourceReadWrite.manager.transaction((transactionalEntityManager) => __awaiter(void 0, void 0, void 0, function* () {
66
- yield processLiveItemBatch(liveItemObjDtosBatch, channel, channelSeasonIndex, existingLiveItemMap, updatedLiveItemItemIds, newItemGuids, transactionalEntityManager, timerAccumulator, liveItemService);
83
+ yield processLiveItemBatch(liveItemObjDtosBatch, channel, channelSeasonIndex, existingLiveItemMap, updatedLiveItemItemIds, pendingItemGuids, liveItemGuids, transactionalEntityManager, timerAccumulator, liveItemService);
67
84
  }));
68
85
  }
69
86
  logTimerAccumulator(timerAccumulator);
@@ -72,6 +89,6 @@ const handleParsedLiveItems = (parsedLiveItems, channel, channelSeasonIndex) =>
72
89
  .filter(liveItem => itemIdsToDelete.includes(liveItem.item.id))
73
90
  .map(liveItem => liveItem.item);
74
91
  yield itemService.updateManyFlagStatus(itemsToDelete, itemFlagStatus_1.ItemFlagStatusStatusEnum.PendingArchive);
75
- return { newItemGuids };
92
+ return { pendingItemGuids, liveItemGuids };
76
93
  });
77
94
  exports.handleParsedLiveItems = handleParsedLiveItems;
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/lib/rss/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAKxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAa,MAAM,oBAAoB,CAAC;AAiC3D,eAAO,MAAM,kBAAkB,GAAU,KAAK,MAAM,wBAUnD,CAAC;AAQF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,0BAA0B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACtC,CAAA;AAED,MAAM,MAAM,oCAAoC,GAAG;IACjD,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,2BAA2B,CAAC;CAClD,CAAA;AAgBD,eAAO,MAAM,6BAA6B,GACxC,KAAK,MAAM,EACX,kBAAkB,MAAM,EACxB,SAAS,oCAAoC;;;;;;EA4I9C,CAAC"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/lib/rss/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EAKxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAa,MAAM,oBAAoB,CAAC;AAmC3D,eAAO,MAAM,kBAAkB,GAAU,KAAK,MAAM,wBAUnD,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,0BAA0B,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACtC,CAAA;AAED,MAAM,MAAM,oCAAoC,GAAG;IACjD,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,2BAA2B,CAAC;CAClD,CAAA;AAgBD,eAAO,MAAM,6BAA6B,GACxC,KAAK,MAAM,EACX,kBAAkB,MAAM,EACxB,SAAS,oCAAoC;;;;;;EAoI9C,CAAC"}
@@ -28,6 +28,8 @@ const loggerService_1 = require("@parser/factories/loggerService");
28
28
  const _request_1 = require("../_request");
29
29
  const parsedFeed_1 = require("./hash/parsedFeed");
30
30
  const config_1 = require("@parser/config");
31
+ const handleNewItemNotifications_1 = require("../notifications/handleNewItemNotifications");
32
+ const handleNewLiveItemNotifications_1 = require("../notifications/handleNewLiveItemNotifications");
31
33
  /*
32
34
  NOTE: All RSS feeds that have a podcast_index_id will be saved to the database.
33
35
  RSS feeds without podcast_index_id (Add By RSS feeds) will NOT be saved to the database.
@@ -107,22 +109,15 @@ const parseRSSFeedAndSaveToDatabase = (url, podcast_index_id, options) => __awai
107
109
  yield (0, channel_1.handleParsedChannel)(parsedFeed, channel, channelSeasonIndex);
108
110
  loggerService_1.loggerService.info(`item count: ${parsedFeed.items.length}`);
109
111
  const newItemIdentifiers = yield (0, item_1.handleParsedItems)(parsedFeed.items, channel, channelSeasonIndex);
110
- let newLiveItemIdentifiers = { newItemGuids: [] };
112
+ let newLiveItemIdentifiers = { pendingItemGuids: [], liveItemGuids: [] };
111
113
  if (parsedFeed.podcastLiveItems) {
112
114
  newLiveItemIdentifiers = yield (0, liveItem_1.handleParsedLiveItems)(parsedFeed.podcastLiveItems, channel, channelSeasonIndex);
113
115
  }
114
- if (newItemIdentifiers.newItemGuids.length > 0 || newLiveItemIdentifiers.newItemGuids.length > 0) {
115
- // const firebaseAccessTokenService = firebaseAccessTokenServiceFactory();
116
- // const googleAuthToken = await firebaseAccessTokenService.generateAccessToken();
117
- // const notificationsService = NotificationsServiceFactory(googleAuthToken);
118
- // const accountFCMDeviceService = new AccountFCMDeviceService();
119
- // const itemService = new ItemService();
120
- // if (newItemIdentifiers.newItemGuids.length > 0) {
121
- // await handleNewItemsNotifications(newItemIdentifiers, channel, notificationsService, accountFCMDeviceService, itemService);
122
- // }
123
- // if (newLiveItemIdentifiers.newItemGuids.length > 0) {
124
- // await handleNewLiveItemsNotifications(newLiveItemIdentifiers, channel, notificationsService, accountFCMDeviceService, itemService);
125
- // }
116
+ if (newItemIdentifiers.newItemGuids.length > 0 || newItemIdentifiers.newItemGuidEnclosureUrls.length > 0) {
117
+ yield (0, handleNewItemNotifications_1.handleNewItemNotifications)(channel, newItemIdentifiers);
118
+ }
119
+ if (newLiveItemIdentifiers.pendingItemGuids.length > 0 || newLiveItemIdentifiers.liveItemGuids.length > 0) {
120
+ yield (0, handleNewLiveItemNotifications_1.handleNewLiveItemNotifications)(channel, newLiveItemIdentifiers);
126
121
  }
127
122
  const feedLogService = new podverse_orm_1.FeedLogService();
128
123
  yield feedLogService.update(feed, { last_finished_parse_time: new Date() });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "podverse-parser",
3
- "version": "5.1.14-alpha.0",
3
+ "version": "5.1.16-alpha.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,9 +17,9 @@
17
17
  "license": "AGPLv3",
18
18
  "dependencies": {
19
19
  "module-alias": "^2.2.3",
20
- "podverse-external-services": "^5.1.14-alpha.0",
21
- "podverse-helpers": "^5.1.14-alpha.0",
22
- "podverse-orm": "^5.1.14-alpha.0",
20
+ "podverse-external-services": "^5.1.16-alpha.0",
21
+ "podverse-helpers": "^5.1.16-alpha.0",
22
+ "podverse-orm": "^5.1.16-alpha.0",
23
23
  "podverse-partytime": "^5.0.0"
24
24
  },
25
25
  "devDependencies": {
@@ -1,3 +0,0 @@
1
- import { FirebaseAccessTokenService } from 'podverse-external-services';
2
- export declare const firebaseAccessTokenServiceFactory: () => FirebaseAccessTokenService;
3
- //# sourceMappingURL=firebaseAccessTokenService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"firebaseAccessTokenService.d.ts","sourceRoot":"","sources":["../../src/factories/firebaseAccessTokenService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAGxE,eAAO,MAAM,iCAAiC,kCAE5C,CAAC"}
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.firebaseAccessTokenServiceFactory = void 0;
4
- const podverse_external_services_1 = require("podverse-external-services");
5
- const config_1 = require("../config");
6
- const firebaseAccessTokenServiceFactory = () => new podverse_external_services_1.FirebaseAccessTokenService({
7
- keyFilePath: config_1.config.firebase.authJsonPath
8
- });
9
- exports.firebaseAccessTokenServiceFactory = firebaseAccessTokenServiceFactory;
@@ -1,3 +0,0 @@
1
- import { NotificationsService } from 'podverse-external-services';
2
- export declare const NotificationsServiceFactory: (googleAuthToken: string) => NotificationsService;
3
- //# sourceMappingURL=notificationsService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"notificationsService.d.ts","sourceRoot":"","sources":["../../src/factories/notificationsService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIlE,eAAO,MAAM,2BAA2B,GAAI,iBAAiB,MAAM,yBAKjE,CAAC"}
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NotificationsServiceFactory = void 0;
4
- const podverse_external_services_1 = require("podverse-external-services");
5
- const loggerService_1 = require("./loggerService");
6
- const config_1 = require("../config");
7
- const NotificationsServiceFactory = (googleAuthToken) => new podverse_external_services_1.NotificationsService({
8
- userAgent: config_1.config.userAgent,
9
- googleAuthToken,
10
- firebaseProjectId: config_1.config.firebase.projectId,
11
- loggerService: loggerService_1.loggerService
12
- });
13
- exports.NotificationsServiceFactory = NotificationsServiceFactory;
@@ -1,8 +0,0 @@
1
- import { NotificationsService, SendNotificationOptions } from "podverse-external-services/dist/services/notifications";
2
- import { AccountFCMDeviceService, Channel, Item, ItemService } from "podverse-orm";
3
- import { HandleParsedItemsResult } from "../rss/item/item";
4
- import { HandleParsedLiveItemsResult } from "../rss/liveItem/liveItem";
5
- export declare const handleNotifications: (items: Item[], accountFCMDeviceService: AccountFCMDeviceService, sendNotificationMethod: (fcmTokens: string[], options: SendNotificationOptions) => Promise<void>) => Promise<void>;
6
- export declare const handleNewItemsNotifications: (newItemIdentifiers: HandleParsedItemsResult, channel: Channel, notificationsService: NotificationsService, accountFCMDeviceService: AccountFCMDeviceService, itemService: ItemService) => Promise<void>;
7
- export declare const handleNewLiveItemsNotifications: (newLiveItemIdentifiers: HandleParsedLiveItemsResult, channel: Channel, notificationsService: NotificationsService, accountFCMDeviceService: AccountFCMDeviceService, itemService: ItemService) => Promise<void>;
8
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,wDAAwD,CAAC;AAEvH,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAEvE,eAAO,MAAM,mBAAmB,GAC9B,OAAO,IAAI,EAAE,EACb,yBAAyB,uBAAuB,EAChD,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,kBAoBjG,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,oBAAoB,uBAAuB,EAC3C,SAAS,OAAO,EAChB,sBAAsB,oBAAoB,EAC1C,yBAAyB,uBAAuB,EAChD,aAAa,WAAW,kBAkBzB,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,wBAAwB,2BAA2B,EACnD,SAAS,OAAO,EAChB,sBAAsB,oBAAoB,EAC1C,yBAAyB,uBAAuB,EAChD,aAAa,WAAW,kBAgBzB,CAAC"}
@@ -1,48 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.handleNewLiveItemsNotifications = exports.handleNewItemsNotifications = exports.handleNotifications = void 0;
13
- const podverse_helpers_1 = require("podverse-helpers");
14
- const handleNotifications = (items, accountFCMDeviceService, sendNotificationMethod) => __awaiter(void 0, void 0, void 0, function* () {
15
- for (const item of items) {
16
- const channel = item.channel;
17
- const fcmTokens = yield accountFCMDeviceService.getFCMTokensByChannelIdText(channel.id_text);
18
- const channelImage = (0, podverse_helpers_1.findImageBySize)(channel.channel_images, 300, 'lesser');
19
- const itemImage = (0, podverse_helpers_1.findImageBySize)(item.item_images, 300, 'lesser');
20
- const sendNotificationOptions = {
21
- itemFullImageUrl: (itemImage === null || itemImage === void 0 ? void 0 : itemImage.url) || null,
22
- itemGuid: item.guid,
23
- itemIdText: item.id_text,
24
- itemTitle: item.title,
25
- channelIdText: item.channel.channel_id_text,
26
- channelFullImageUrl: (channelImage === null || channelImage === void 0 ? void 0 : channelImage.url) || null,
27
- channelTitle: item.channel.title
28
- };
29
- yield sendNotificationMethod(fcmTokens, sendNotificationOptions);
30
- }
31
- });
32
- exports.handleNotifications = handleNotifications;
33
- const handleNewItemsNotifications = (newItemIdentifiers, channel, notificationsService, accountFCMDeviceService, itemService) => __awaiter(void 0, void 0, void 0, function* () {
34
- const itemsByGuid = yield itemService.getManyByGuid(channel, newItemIdentifiers.newItemGuids, {
35
- relations: ['channel', 'channel.channel_images', 'item_images']
36
- });
37
- const itemsByGuidEnclosureUrl = yield itemService.getManyByGuidEnclosureUrl(channel, newItemIdentifiers.newItemGuids);
38
- const itemsToNotify = itemsByGuid.concat(itemsByGuidEnclosureUrl);
39
- yield (0, exports.handleNotifications)(itemsToNotify, accountFCMDeviceService, notificationsService.sendNewItemDetectedNotifications);
40
- });
41
- exports.handleNewItemsNotifications = handleNewItemsNotifications;
42
- const handleNewLiveItemsNotifications = (newLiveItemIdentifiers, channel, notificationsService, accountFCMDeviceService, itemService) => __awaiter(void 0, void 0, void 0, function* () {
43
- const itemsByGuid = yield itemService.getManyByGuid(channel, newLiveItemIdentifiers.newItemGuids, {
44
- relations: ['channel', 'channel.channel_images', 'item_images']
45
- });
46
- yield (0, exports.handleNotifications)(itemsByGuid, accountFCMDeviceService, notificationsService.sendLiveItemLiveDetectedNotifications);
47
- });
48
- exports.handleNewLiveItemsNotifications = handleNewLiveItemsNotifications;