mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
feat(backend): export playlists functionality
Entire-Checkpoint: c6e522b4276c
This commit is contained in:
1 parent
04d2800ab1
commit
1c1a53743a
10 files changed
+276
-185
No files matched your search
@@ -396,22 +396,18 @@ const electronApi = {
|
||||
dbDeletePlaylist: (playlistId: string, operationId?: string) =>
|
||||
ipcRenderer.invoke('DB_DELETE_PLAYLIST', playlistId, operationId),
|
||||
dbDeleteXtreamContent: (playlistId: string, operationId?: string) =>
|
||||
ipcRenderer.invoke(
|
||||
'DB_DELETE_XTREAM_CONTENT',
|
||||
playlistId,
|
||||
operationId
|
||||
),
|
||||
ipcRenderer.invoke('DB_DELETE_XTREAM_CONTENT', playlistId, operationId),
|
||||
dbRestoreXtreamUserData: (
|
||||
playlistId: string,
|
||||
favoritedXtreamIds: number[],
|
||||
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[],
|
||||
favorites: unknown[],
|
||||
recentlyViewed: unknown[],
|
||||
operationId?: string
|
||||
) =>
|
||||
ipcRenderer.invoke(
|
||||
'DB_RESTORE_XTREAM_USER_DATA',
|
||||
playlistId,
|
||||
favoritedXtreamIds,
|
||||
recentlyViewedXtreamIds,
|
||||
favorites,
|
||||
recentlyViewed,
|
||||
operationId
|
||||
),
|
||||
dbHasCategories: (playlistId: string, type: string) =>
|
||||
@@ -500,7 +496,8 @@ const electronApi = {
|
||||
dbGetFavorites: (playlistId: string) =>
|
||||
ipcRenderer.invoke('DB_GET_FAVORITES', playlistId),
|
||||
dbGetGlobalFavorites: () => ipcRenderer.invoke('DB_GET_GLOBAL_FAVORITES'),
|
||||
dbGetAllGlobalFavorites: () => ipcRenderer.invoke('DB_GET_ALL_GLOBAL_FAVORITES'),
|
||||
dbGetAllGlobalFavorites: () =>
|
||||
ipcRenderer.invoke('DB_GET_ALL_GLOBAL_FAVORITES'),
|
||||
dbReorderGlobalFavorites: (
|
||||
updates: { content_id: number; position: number }[]
|
||||
) => ipcRenderer.invoke('DB_REORDER_GLOBAL_FAVORITES', updates),
|
||||
@@ -562,6 +559,8 @@ const electronApi = {
|
||||
),
|
||||
dbGetAllPlaybackPositions: (playlistId: string) =>
|
||||
ipcRenderer.invoke('DB_GET_ALL_PLAYBACK_POSITIONS', playlistId),
|
||||
dbClearAllPlaybackPositions: (playlistId: string) =>
|
||||
ipcRenderer.invoke('DB_CLEAR_ALL_PLAYBACK_POSITIONS', playlistId),
|
||||
dbClearPlaybackPosition: (
|
||||
playlistId: string,
|
||||
contentXtreamId: number,
|
||||
|
||||
@@ -58,10 +58,7 @@ export async function isFavorite(
|
||||
return result[0].count > 0;
|
||||
}
|
||||
|
||||
export async function getFavorites(
|
||||
db: AppDatabase,
|
||||
playlistId: string
|
||||
) {
|
||||
export async function getFavorites(db: AppDatabase, playlistId: string) {
|
||||
return db
|
||||
.select({
|
||||
id: schema.content.id,
|
||||
@@ -73,6 +70,7 @@ export async function getFavorites(
|
||||
xtream_id: schema.content.xtreamId,
|
||||
type: schema.content.type,
|
||||
added_at: schema.favorites.addedAt,
|
||||
position: schema.favorites.position,
|
||||
})
|
||||
.from(schema.favorites)
|
||||
.innerJoin(
|
||||
@@ -80,7 +78,10 @@ export async function getFavorites(
|
||||
eq(schema.favorites.contentId, schema.content.id)
|
||||
)
|
||||
.where(eq(schema.favorites.playlistId, playlistId))
|
||||
.orderBy(desc(schema.favorites.addedAt));
|
||||
.orderBy(
|
||||
asc(schema.favorites.position),
|
||||
desc(schema.favorites.addedAt)
|
||||
);
|
||||
}
|
||||
|
||||
export async function getGlobalFavorites(db: AppDatabase) {
|
||||
|
||||
@@ -2,12 +2,7 @@ import { and, desc, eq, sql } from 'drizzle-orm';
|
||||
import * as schema from 'database-schema';
|
||||
import type { AppDatabase } from '../database.types';
|
||||
|
||||
type PlaylistType =
|
||||
| 'xtream'
|
||||
| 'stalker'
|
||||
| 'm3u-file'
|
||||
| 'm3u-text'
|
||||
| 'm3u-url';
|
||||
type PlaylistType = 'xtream' | 'stalker' | 'm3u-file' | 'm3u-text' | 'm3u-url';
|
||||
|
||||
type PlaybackPositionPayload = {
|
||||
contentXtreamId: number;
|
||||
@@ -98,10 +93,7 @@ export async function getPlaybackPosition(
|
||||
.where(
|
||||
and(
|
||||
eq(schema.playbackPositions.playlistId, playlistId),
|
||||
eq(
|
||||
schema.playbackPositions.contentXtreamId,
|
||||
contentXtreamId
|
||||
),
|
||||
eq(schema.playbackPositions.contentXtreamId, contentXtreamId),
|
||||
eq(schema.playbackPositions.contentType, contentType)
|
||||
)
|
||||
)
|
||||
@@ -150,6 +142,17 @@ export async function getAllPlaybackPositions(
|
||||
.where(eq(schema.playbackPositions.playlistId, playlistId));
|
||||
}
|
||||
|
||||
export async function clearAllPlaybackPositions(
|
||||
db: AppDatabase,
|
||||
playlistId: string
|
||||
): Promise<{ success: boolean }> {
|
||||
await db
|
||||
.delete(schema.playbackPositions)
|
||||
.where(eq(schema.playbackPositions.playlistId, playlistId));
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export async function clearPlaybackPosition(
|
||||
db: AppDatabase,
|
||||
playlistId: string,
|
||||
@@ -161,10 +164,7 @@ export async function clearPlaybackPosition(
|
||||
.where(
|
||||
and(
|
||||
eq(schema.playbackPositions.playlistId, playlistId),
|
||||
eq(
|
||||
schema.playbackPositions.contentXtreamId,
|
||||
contentXtreamId
|
||||
),
|
||||
eq(schema.playbackPositions.contentXtreamId, contentXtreamId),
|
||||
eq(schema.playbackPositions.contentType, contentType)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { and, eq, inArray } from 'drizzle-orm';
|
||||
import * as schema from 'database-schema';
|
||||
import type {
|
||||
XtreamBackupFavoriteItem,
|
||||
XtreamBackupHiddenCategory,
|
||||
XtreamBackupRecentlyViewedItem,
|
||||
} from 'shared-interfaces';
|
||||
import type { AppDatabase } from '../database.types';
|
||||
import {
|
||||
checkpointOperation,
|
||||
@@ -10,15 +15,28 @@ import {
|
||||
|
||||
const DEFAULT_BATCH_SIZE = 100;
|
||||
|
||||
type ContentIdentity = {
|
||||
id: number;
|
||||
xtreamId: number;
|
||||
contentType: XtreamBackupFavoriteItem['contentType'];
|
||||
};
|
||||
|
||||
function toContentIdentityKey(
|
||||
contentType: XtreamBackupFavoriteItem['contentType'],
|
||||
xtreamId: number
|
||||
): string {
|
||||
return `${contentType}:${xtreamId}`;
|
||||
}
|
||||
|
||||
export async function deleteXtreamContent(
|
||||
db: AppDatabase,
|
||||
playlistId: string,
|
||||
control?: OperationControl
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
favoritedXtreamIds: number[];
|
||||
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[];
|
||||
hiddenCategories: { xtreamId: number; type: string }[];
|
||||
favorites: XtreamBackupFavoriteItem[];
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[];
|
||||
hiddenCategories: XtreamBackupHiddenCategory[];
|
||||
}> {
|
||||
const categories = await db
|
||||
.select({
|
||||
@@ -35,16 +53,19 @@ export async function deleteXtreamContent(
|
||||
.filter((category) => category.hidden)
|
||||
.map((category) => ({
|
||||
xtreamId: category.xtreamId,
|
||||
type: category.type,
|
||||
categoryType: category.type,
|
||||
}));
|
||||
|
||||
let favoritedXtreamIds: number[] = [];
|
||||
let recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[] = [];
|
||||
let favorites: XtreamBackupFavoriteItem[] = [];
|
||||
let recentlyViewed: XtreamBackupRecentlyViewedItem[] = [];
|
||||
|
||||
if (categoryIds.length > 0) {
|
||||
const favorites = await db
|
||||
const favoritedContent = await db
|
||||
.select({
|
||||
xtreamId: schema.content.xtreamId,
|
||||
contentType: schema.content.type,
|
||||
addedAt: schema.favorites.addedAt,
|
||||
position: schema.favorites.position,
|
||||
})
|
||||
.from(schema.favorites)
|
||||
.innerJoin(
|
||||
@@ -58,11 +79,17 @@ export async function deleteXtreamContent(
|
||||
)
|
||||
);
|
||||
|
||||
favoritedXtreamIds = favorites.map((favorite) => favorite.xtreamId);
|
||||
favorites = favoritedContent.map((favorite) => ({
|
||||
xtreamId: favorite.xtreamId,
|
||||
contentType: favorite.contentType,
|
||||
addedAt: favorite.addedAt ?? undefined,
|
||||
position: favorite.position,
|
||||
}));
|
||||
|
||||
const recentlyViewed = await db
|
||||
const recentlyViewedContent = await db
|
||||
.select({
|
||||
xtreamId: schema.content.xtreamId,
|
||||
contentType: schema.content.type,
|
||||
viewedAt: schema.recentlyViewed.viewedAt,
|
||||
})
|
||||
.from(schema.recentlyViewed)
|
||||
@@ -77,8 +104,9 @@ export async function deleteXtreamContent(
|
||||
)
|
||||
);
|
||||
|
||||
recentlyViewedXtreamIds = recentlyViewed.map((item) => ({
|
||||
recentlyViewed = recentlyViewedContent.map((item) => ({
|
||||
xtreamId: item.xtreamId,
|
||||
contentType: item.contentType,
|
||||
viewedAt: item.viewedAt || new Date().toISOString(),
|
||||
}));
|
||||
|
||||
@@ -127,119 +155,164 @@ export async function deleteXtreamContent(
|
||||
|
||||
return {
|
||||
success: true,
|
||||
favoritedXtreamIds,
|
||||
recentlyViewedXtreamIds,
|
||||
favorites,
|
||||
recentlyViewed,
|
||||
hiddenCategories,
|
||||
};
|
||||
}
|
||||
|
||||
async function getContentIdentityMap(
|
||||
db: AppDatabase,
|
||||
playlistId: string,
|
||||
identities: Array<{
|
||||
contentType: XtreamBackupFavoriteItem['contentType'];
|
||||
xtreamId: number;
|
||||
}>
|
||||
): Promise<Map<string, number>> {
|
||||
const xtreamIds = Array.from(
|
||||
new Set(identities.map((item) => item.xtreamId))
|
||||
);
|
||||
|
||||
if (xtreamIds.length === 0) {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
const content = await db
|
||||
.select({
|
||||
id: schema.content.id,
|
||||
xtreamId: schema.content.xtreamId,
|
||||
contentType: schema.content.type,
|
||||
})
|
||||
.from(schema.content)
|
||||
.innerJoin(
|
||||
schema.categories,
|
||||
eq(schema.content.categoryId, schema.categories.id)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.categories.playlistId, playlistId),
|
||||
inArray(schema.content.xtreamId, xtreamIds)
|
||||
)
|
||||
);
|
||||
|
||||
return new Map(
|
||||
content.map((item: ContentIdentity) => [
|
||||
toContentIdentityKey(item.contentType, item.xtreamId),
|
||||
item.id,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
export async function restoreXtreamUserData(
|
||||
db: AppDatabase,
|
||||
playlistId: string,
|
||||
favoritedXtreamIds: number[],
|
||||
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[],
|
||||
favorites: XtreamBackupFavoriteItem[],
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[],
|
||||
control?: OperationControl
|
||||
): Promise<{ success: boolean }> {
|
||||
if (favoritedXtreamIds.length > 0) {
|
||||
const content = await db
|
||||
.select({
|
||||
id: schema.content.id,
|
||||
xtreamId: schema.content.xtreamId,
|
||||
})
|
||||
.from(schema.content)
|
||||
.innerJoin(
|
||||
schema.categories,
|
||||
eq(schema.content.categoryId, schema.categories.id)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.categories.playlistId, playlistId),
|
||||
inArray(schema.content.xtreamId, favoritedXtreamIds)
|
||||
)
|
||||
await checkpointOperation(control);
|
||||
await db
|
||||
.delete(schema.favorites)
|
||||
.where(eq(schema.favorites.playlistId, playlistId));
|
||||
|
||||
await checkpointOperation(control);
|
||||
await db
|
||||
.delete(schema.recentlyViewed)
|
||||
.where(eq(schema.recentlyViewed.playlistId, playlistId));
|
||||
|
||||
const contentByIdentity = await getContentIdentityMap(db, playlistId, [
|
||||
...favorites.map((item) => ({
|
||||
contentType: item.contentType,
|
||||
xtreamId: item.xtreamId,
|
||||
})),
|
||||
...recentlyViewed.map((item) => ({
|
||||
contentType: item.contentType,
|
||||
xtreamId: item.xtreamId,
|
||||
})),
|
||||
]);
|
||||
|
||||
const favoriteValues = favorites
|
||||
.map((item, index) => {
|
||||
const contentId = contentByIdentity.get(
|
||||
toContentIdentityKey(item.contentType, item.xtreamId)
|
||||
);
|
||||
|
||||
let currentFavorites = 0;
|
||||
const totalFavorites = content.length;
|
||||
if (!contentId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const chunk of chunkValues(content, DEFAULT_BATCH_SIZE)) {
|
||||
await checkpointOperation(control);
|
||||
await db.insert(schema.favorites).values(
|
||||
chunk.map((item) => ({
|
||||
contentId: item.id,
|
||||
playlistId,
|
||||
addedAt: new Date().toISOString(),
|
||||
}))
|
||||
);
|
||||
currentFavorites += chunk.length;
|
||||
await reportOperationProgress(control, {
|
||||
phase: 'restoring-favorites',
|
||||
current: currentFavorites,
|
||||
total: totalFavorites,
|
||||
increment: chunk.length,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (recentlyViewedXtreamIds.length > 0) {
|
||||
const xtreamIds = recentlyViewedXtreamIds.map((item) => item.xtreamId);
|
||||
const content = await db
|
||||
.select({
|
||||
id: schema.content.id,
|
||||
xtreamId: schema.content.xtreamId,
|
||||
})
|
||||
.from(schema.content)
|
||||
.innerJoin(
|
||||
schema.categories,
|
||||
eq(schema.content.categoryId, schema.categories.id)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.categories.playlistId, playlistId),
|
||||
inArray(schema.content.xtreamId, xtreamIds)
|
||||
)
|
||||
);
|
||||
|
||||
const xtreamIdToContentId = new Map(
|
||||
content.map((item) => [item.xtreamId, item.id])
|
||||
return {
|
||||
contentId,
|
||||
playlistId,
|
||||
addedAt: item.addedAt ?? new Date().toISOString(),
|
||||
position: item.position ?? index,
|
||||
};
|
||||
})
|
||||
.filter(
|
||||
(
|
||||
value
|
||||
): value is {
|
||||
contentId: number;
|
||||
playlistId: string;
|
||||
addedAt: string;
|
||||
position: number | null;
|
||||
} => value !== null
|
||||
);
|
||||
|
||||
const values = recentlyViewedXtreamIds
|
||||
.map((item) => {
|
||||
const contentId = xtreamIdToContentId.get(item.xtreamId);
|
||||
if (!contentId) {
|
||||
return null;
|
||||
}
|
||||
let restoredFavorites = 0;
|
||||
const totalFavorites = favoriteValues.length;
|
||||
|
||||
return {
|
||||
contentId,
|
||||
playlistId,
|
||||
viewedAt: item.viewedAt,
|
||||
};
|
||||
})
|
||||
.filter(
|
||||
(
|
||||
value
|
||||
): value is {
|
||||
contentId: number;
|
||||
playlistId: string;
|
||||
viewedAt: string;
|
||||
} => value !== null
|
||||
for (const chunk of chunkValues(favoriteValues, DEFAULT_BATCH_SIZE)) {
|
||||
await checkpointOperation(control);
|
||||
await db.insert(schema.favorites).values(chunk);
|
||||
restoredFavorites += chunk.length;
|
||||
await reportOperationProgress(control, {
|
||||
phase: 'restoring-favorites',
|
||||
current: restoredFavorites,
|
||||
total: totalFavorites,
|
||||
increment: chunk.length,
|
||||
});
|
||||
}
|
||||
|
||||
const recentlyViewedValues = recentlyViewed
|
||||
.map((item) => {
|
||||
const contentId = contentByIdentity.get(
|
||||
toContentIdentityKey(item.contentType, item.xtreamId)
|
||||
);
|
||||
|
||||
let currentRecentlyViewed = 0;
|
||||
const totalRecentlyViewed = values.length;
|
||||
if (!contentId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const chunk of chunkValues(values, DEFAULT_BATCH_SIZE)) {
|
||||
await checkpointOperation(control);
|
||||
await db.insert(schema.recentlyViewed).values(chunk);
|
||||
currentRecentlyViewed += chunk.length;
|
||||
await reportOperationProgress(control, {
|
||||
phase: 'restoring-recently-viewed',
|
||||
current: currentRecentlyViewed,
|
||||
total: totalRecentlyViewed,
|
||||
increment: chunk.length,
|
||||
});
|
||||
}
|
||||
return {
|
||||
contentId,
|
||||
playlistId,
|
||||
viewedAt: item.viewedAt,
|
||||
};
|
||||
})
|
||||
.filter(
|
||||
(
|
||||
value
|
||||
): value is {
|
||||
contentId: number;
|
||||
playlistId: string;
|
||||
viewedAt: string;
|
||||
} => value !== null
|
||||
);
|
||||
|
||||
let restoredRecentlyViewed = 0;
|
||||
const totalRecentlyViewed = recentlyViewedValues.length;
|
||||
|
||||
for (const chunk of chunkValues(recentlyViewedValues, DEFAULT_BATCH_SIZE)) {
|
||||
await checkpointOperation(control);
|
||||
await db.insert(schema.recentlyViewed).values(chunk);
|
||||
restoredRecentlyViewed += chunk.length;
|
||||
await reportOperationProgress(control, {
|
||||
phase: 'restoring-recently-viewed',
|
||||
current: restoredRecentlyViewed,
|
||||
total: totalRecentlyViewed,
|
||||
increment: chunk.length,
|
||||
});
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
|
||||
@@ -42,8 +42,12 @@ handleWorkerRequest(
|
||||
})
|
||||
);
|
||||
|
||||
handleWorkerRequest('DB_GET_ALL_PLAYBACK_POSITIONS', (playlistId: string) => ({
|
||||
playlistId,
|
||||
}));
|
||||
|
||||
handleWorkerRequest(
|
||||
'DB_GET_ALL_PLAYBACK_POSITIONS',
|
||||
'DB_CLEAR_ALL_PLAYBACK_POSITIONS',
|
||||
(playlistId: string) => ({
|
||||
playlistId,
|
||||
})
|
||||
|
||||
@@ -30,8 +30,8 @@ ipcMain.handle(
|
||||
async (
|
||||
event,
|
||||
playlistId: string,
|
||||
favoritedXtreamIds: number[],
|
||||
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[],
|
||||
favorites: unknown[],
|
||||
recentlyViewed: unknown[],
|
||||
operationId?: string
|
||||
) => {
|
||||
try {
|
||||
@@ -40,8 +40,8 @@ ipcMain.handle(
|
||||
'DB_RESTORE_XTREAM_USER_DATA',
|
||||
{
|
||||
playlistId,
|
||||
favoritedXtreamIds,
|
||||
recentlyViewedXtreamIds,
|
||||
favorites,
|
||||
recentlyViewed,
|
||||
operationId,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -43,6 +43,7 @@ export const DB_WORKER_OPERATIONS = [
|
||||
'DB_GET_SERIES_PLAYBACK_POSITIONS',
|
||||
'DB_GET_RECENT_PLAYBACK_POSITIONS',
|
||||
'DB_GET_ALL_PLAYBACK_POSITIONS',
|
||||
'DB_CLEAR_ALL_PLAYBACK_POSITIONS',
|
||||
'DB_CLEAR_PLAYBACK_POSITION',
|
||||
] as const;
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@ import {
|
||||
getWorkerDatabase,
|
||||
} from './database.worker-connection';
|
||||
import { parentPort } from 'worker_threads';
|
||||
import type {
|
||||
XtreamBackupFavoriteItem,
|
||||
XtreamBackupRecentlyViewedItem,
|
||||
} from 'shared-interfaces';
|
||||
import type {
|
||||
DbOperationEvent,
|
||||
DbWorkerIncomingMessage,
|
||||
@@ -40,6 +44,7 @@ import {
|
||||
searchContent,
|
||||
} from '../database/operations/content.operations';
|
||||
import {
|
||||
clearAllPlaybackPositions,
|
||||
clearPlaybackPosition,
|
||||
getAllPlaybackPositions,
|
||||
getPlaybackPosition,
|
||||
@@ -167,9 +172,7 @@ function createOperationController(config: {
|
||||
const { operationId, operation, playlistId, requestId } = config;
|
||||
const cancellable = config.cancellable ?? true;
|
||||
const activeState =
|
||||
operationId && cancellable
|
||||
? { cancelled: false }
|
||||
: null;
|
||||
operationId && cancellable ? { cancelled: false } : null;
|
||||
|
||||
if (operationId && activeState) {
|
||||
activeOperations.set(operationId, activeState);
|
||||
@@ -232,8 +235,7 @@ function createOperationController(config: {
|
||||
emitError: (error, event) => {
|
||||
send('error', {
|
||||
...event,
|
||||
error:
|
||||
error instanceof Error ? error.message : String(error),
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
},
|
||||
cleanup: () => {
|
||||
@@ -614,8 +616,8 @@ async function executeRequest(message: DbWorkerRequestMessage) {
|
||||
case 'DB_RESTORE_XTREAM_USER_DATA': {
|
||||
const payload = message.payload as {
|
||||
playlistId: string;
|
||||
favoritedXtreamIds: number[];
|
||||
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[];
|
||||
favorites: XtreamBackupFavoriteItem[];
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[];
|
||||
operationId?: string;
|
||||
};
|
||||
|
||||
@@ -628,8 +630,8 @@ async function executeRequest(message: DbWorkerRequestMessage) {
|
||||
},
|
||||
async (controller) => {
|
||||
const totalItems =
|
||||
payload.favoritedXtreamIds.length +
|
||||
payload.recentlyViewedXtreamIds.length;
|
||||
payload.favorites.length +
|
||||
payload.recentlyViewed.length;
|
||||
controller.emitStarted({
|
||||
phase: DB_OPERATION_PHASES.RESTORING_FAVORITES,
|
||||
current: 0,
|
||||
@@ -639,8 +641,8 @@ async function executeRequest(message: DbWorkerRequestMessage) {
|
||||
const result = await restoreXtreamUserData(
|
||||
db,
|
||||
payload.playlistId,
|
||||
payload.favoritedXtreamIds,
|
||||
payload.recentlyViewedXtreamIds,
|
||||
payload.favorites,
|
||||
payload.recentlyViewed,
|
||||
controller.control
|
||||
);
|
||||
|
||||
@@ -740,7 +742,12 @@ async function executeRequest(message: DbWorkerRequestMessage) {
|
||||
episodeNumber?: number;
|
||||
positionSeconds: number;
|
||||
durationSeconds?: number;
|
||||
playlistType?: 'xtream' | 'stalker' | 'm3u-file' | 'm3u-text' | 'm3u-url';
|
||||
playlistType?:
|
||||
| 'xtream'
|
||||
| 'stalker'
|
||||
| 'm3u-file'
|
||||
| 'm3u-text'
|
||||
| 'm3u-url';
|
||||
};
|
||||
};
|
||||
return savePlaybackPosition(db, payload.playlistId, payload.data);
|
||||
@@ -789,6 +796,11 @@ async function executeRequest(message: DbWorkerRequestMessage) {
|
||||
return getAllPlaybackPositions(db, payload.playlistId);
|
||||
}
|
||||
|
||||
case 'DB_CLEAR_ALL_PLAYBACK_POSITIONS': {
|
||||
const payload = message.payload as { playlistId: string };
|
||||
return clearAllPlaybackPositions(db, payload.playlistId);
|
||||
}
|
||||
|
||||
case 'DB_CLEAR_PLAYBACK_POSITION': {
|
||||
const payload = message.payload as {
|
||||
playlistId: string;
|
||||
@@ -823,7 +835,11 @@ parentPort.on('message', async (message: DbWorkerIncomingMessage) => {
|
||||
result,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(loggerLabel, `Error handling ${message.operation}:`, error);
|
||||
console.error(
|
||||
loggerLabel,
|
||||
`Error handling ${message.operation}:`,
|
||||
error
|
||||
);
|
||||
postMessage({
|
||||
type: 'response',
|
||||
requestId: message.requestId,
|
||||
|
||||
Vendored
+12
-17
@@ -14,6 +14,9 @@ import {
|
||||
PlaylistRefreshEvent,
|
||||
PlaylistRefreshPayload,
|
||||
PortalDebugEvent,
|
||||
XtreamBackupFavoriteItem,
|
||||
XtreamBackupHiddenCategory,
|
||||
XtreamBackupRecentlyViewedItem,
|
||||
XtreamCategory,
|
||||
} from 'shared-interfaces';
|
||||
import {
|
||||
@@ -81,9 +84,7 @@ declare global {
|
||||
headers?: Record<string, string>
|
||||
) => Promise<ExternalPlayerSession>;
|
||||
autoUpdatePlaylists: (playlists: Playlist[]) => Promise<Playlist[]>;
|
||||
fetchEpg: (
|
||||
urls: string[]
|
||||
) => Promise<{
|
||||
fetchEpg: (urls: string[]) => Promise<{
|
||||
success: boolean;
|
||||
message?: string;
|
||||
skipped?: string[];
|
||||
@@ -171,23 +172,14 @@ declare global {
|
||||
operationId?: string
|
||||
) => Promise<{
|
||||
success: boolean;
|
||||
favoritedXtreamIds: number[];
|
||||
recentlyViewedXtreamIds: {
|
||||
xtreamId: number;
|
||||
viewedAt: string;
|
||||
}[];
|
||||
hiddenCategories: {
|
||||
xtreamId: number;
|
||||
type: string;
|
||||
}[];
|
||||
favorites: XtreamBackupFavoriteItem[];
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[];
|
||||
hiddenCategories: XtreamBackupHiddenCategory[];
|
||||
}>;
|
||||
dbRestoreXtreamUserData: (
|
||||
playlistId: string,
|
||||
favoritedXtreamIds: number[],
|
||||
recentlyViewedXtreamIds: {
|
||||
xtreamId: number;
|
||||
viewedAt: string;
|
||||
}[],
|
||||
favorites: XtreamBackupFavoriteItem[],
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[],
|
||||
operationId?: string
|
||||
) => Promise<{ success: boolean }>;
|
||||
dbHasCategories: (
|
||||
@@ -381,6 +373,9 @@ declare global {
|
||||
dbGetAllPlaybackPositions: (
|
||||
playlistId: string
|
||||
) => Promise<PlaybackPositionData[]>;
|
||||
dbClearAllPlaybackPositions: (
|
||||
playlistId: string
|
||||
) => Promise<{ success: boolean }>;
|
||||
dbClearPlaybackPosition: (
|
||||
playlistId: string,
|
||||
contentXtreamId: number,
|
||||
|
||||
Vendored
+18
-16
@@ -1,5 +1,11 @@
|
||||
import 'jest-extended';
|
||||
import { ExternalPlayerSession } from './libs/shared/interfaces/src/lib/external-player-session.interface';
|
||||
import { PlaybackPositionData } from './libs/shared/interfaces/src/lib/playback-position.interface';
|
||||
import {
|
||||
XtreamBackupFavoriteItem,
|
||||
XtreamBackupHiddenCategory,
|
||||
XtreamBackupRecentlyViewedItem,
|
||||
} from './libs/shared/interfaces/src/lib/playlist-backup.interface';
|
||||
import {
|
||||
PlaylistRefreshEvent,
|
||||
PlaylistRefreshPayload,
|
||||
@@ -156,23 +162,14 @@ declare global {
|
||||
operationId?: string
|
||||
) => Promise<{
|
||||
success: boolean;
|
||||
favoritedXtreamIds: number[];
|
||||
recentlyViewedXtreamIds: {
|
||||
xtreamId: number;
|
||||
viewedAt: string;
|
||||
}[];
|
||||
hiddenCategories: {
|
||||
xtreamId: number;
|
||||
type: string;
|
||||
}[];
|
||||
favorites: XtreamBackupFavoriteItem[];
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[];
|
||||
hiddenCategories: XtreamBackupHiddenCategory[];
|
||||
}>;
|
||||
dbRestoreXtreamUserData: (
|
||||
playlistId: string,
|
||||
favoritedXtreamIds: number[],
|
||||
recentlyViewedXtreamIds: {
|
||||
xtreamId: number;
|
||||
viewedAt: string;
|
||||
}[],
|
||||
favorites: XtreamBackupFavoriteItem[],
|
||||
recentlyViewed: XtreamBackupRecentlyViewedItem[],
|
||||
operationId?: string
|
||||
) => Promise<{ success: boolean }>;
|
||||
dbHasCategories: (
|
||||
@@ -346,8 +343,13 @@ declare global {
|
||||
dbGetRecentPlaybackPositions: (
|
||||
playlistId: string,
|
||||
limit?: number
|
||||
) => Promise<any[]>;
|
||||
dbGetAllPlaybackPositions: (playlistId: string) => Promise<any[]>;
|
||||
) => Promise<PlaybackPositionData[]>;
|
||||
dbGetAllPlaybackPositions: (
|
||||
playlistId: string
|
||||
) => Promise<PlaybackPositionData[]>;
|
||||
dbClearAllPlaybackPositions: (
|
||||
playlistId: string
|
||||
) => Promise<{ success: boolean }>;
|
||||
dbClearPlaybackPosition: (
|
||||
playlistId: string,
|
||||
contentXtreamId: number,
|
||||
|
||||
Reference in new issue
Block a user