podverse-parser 5.1.15-alpha.0 → 5.1.16-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/notifications/handleNewItemNotifications.d.ts +7 -0
- package/dist/lib/notifications/handleNewItemNotifications.d.ts.map +1 -0
- package/dist/lib/notifications/handleNewItemNotifications.js +112 -0
- package/dist/lib/notifications/handleNewLiveItemNotifications.d.ts +9 -0
- package/dist/lib/notifications/handleNewLiveItemNotifications.d.ts.map +1 -0
- package/dist/lib/notifications/handleNewLiveItemNotifications.js +94 -0
- package/dist/lib/notifications/sharedNotificationHelpers.d.ts +54 -0
- package/dist/lib/notifications/sharedNotificationHelpers.d.ts.map +1 -0
- package/dist/lib/notifications/sharedNotificationHelpers.js +206 -0
- package/dist/lib/rss/liveItem/liveItem.d.ts +4 -1
- package/dist/lib/rss/liveItem/liveItem.d.ts.map +1 -1
- package/dist/lib/rss/liveItem/liveItem.js +25 -8
- package/dist/lib/rss/parser.d.ts.map +1 -1
- package/dist/lib/rss/parser.js +8 -13
- package/package.json +4 -4
- package/dist/factories/firebaseAccessTokenService.d.ts +0 -3
- package/dist/factories/firebaseAccessTokenService.d.ts.map +0 -1
- package/dist/factories/firebaseAccessTokenService.js +0 -9
- package/dist/factories/notificationsService.d.ts +0 -3
- package/dist/factories/notificationsService.d.ts.map +0 -1
- package/dist/factories/notificationsService.js +0 -13
- package/dist/lib/notifications/index.d.ts +0 -8
- package/dist/lib/notifications/index.d.ts.map +0 -1
- package/dist/lib/notifications/index.js +0 -48
|
@@ -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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
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,
|
|
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 {
|
|
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;
|
|
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"}
|
package/dist/lib/rss/parser.js
CHANGED
|
@@ -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 = {
|
|
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 ||
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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.
|
|
3
|
+
"version": "5.1.16-alpha.1",
|
|
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.
|
|
21
|
-
"podverse-helpers": "^5.1.
|
|
22
|
-
"podverse-orm": "^5.1.
|
|
20
|
+
"podverse-external-services": "^5.1.17-alpha.0",
|
|
21
|
+
"podverse-helpers": "^5.1.17-alpha.0",
|
|
22
|
+
"podverse-orm": "^5.1.17-alpha.0",
|
|
23
23
|
"podverse-partytime": "^5.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
@@ -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 +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;
|