feat: restore hidden category state after playlist refresh

This commit is contained in:
4gray committed 2026-01-11 21:20:50 +01:00
1 parent afd8da0c25
commit 2630025b11
7 files changed
+105 -16

No files matched your search

@@ -129,8 +129,19 @@ contextBridge.exposeInMainWorld('electron', {
ipcRenderer.invoke('DB_HAS_CATEGORIES', playlistId, type),
dbGetCategories: (playlistId: string, type: string) =>
ipcRenderer.invoke('DB_GET_CATEGORIES', playlistId, type),
dbSaveCategories: (playlistId: string, categories: any[], type: string) =>
ipcRenderer.invoke('DB_SAVE_CATEGORIES', playlistId, categories, type),
dbSaveCategories: (
playlistId: string,
categories: any[],
type: string,
hiddenCategoryXtreamIds?: number[]
) =>
ipcRenderer.invoke(
'DB_SAVE_CATEGORIES',
playlistId,
categories,
type,
hiddenCategoryXtreamIds
),
dbGetAllCategories: (playlistId: string, type: string) =>
ipcRenderer.invoke('DB_GET_ALL_CATEGORIES', playlistId, type),
dbUpdateCategoryVisibility: (categoryIds: number[], hidden: boolean) =>
@@ -62,6 +62,7 @@ ipcMain.handle(
/**
* Save categories in bulk
* Optionally accepts hidden category data to restore visibility preferences
*/
ipcMain.handle(
'DB_SAVE_CATEGORIES',
@@ -72,7 +73,8 @@ ipcMain.handle(
category_name: string;
category_id: number;
}>,
type: 'live' | 'movies' | 'series'
type: 'live' | 'movies' | 'series',
hiddenCategoryXtreamIds?: number[]
) => {
try {
// Skip if no categories to save
@@ -81,11 +83,17 @@ ipcMain.handle(
}
const db = await getDatabase();
// Create a Set of hidden xtreamIds for efficient lookup
const hiddenSet = new Set(hiddenCategoryXtreamIds || []);
const values = categories.map((cat) => ({
playlistId,
name: cat.category_name,
type,
xtreamId: cat.category_id,
// Restore hidden status if the category was previously hidden
hidden: hiddenSet.has(cat.category_id),
}));
await db.insert(schema.categories).values(values);
@@ -18,14 +18,27 @@ ipcMain.handle(
try {
const db = await getDatabase();
// First, get all category IDs for this playlist
// First, get all categories for this playlist (including hidden status)
const categories = await db
.select({ id: schema.categories.id })
.select({
id: schema.categories.id,
xtreamId: schema.categories.xtreamId,
type: schema.categories.type,
hidden: schema.categories.hidden,
})
.from(schema.categories)
.where(eq(schema.categories.playlistId, playlistId));
const categoryIds = categories.map((c) => c.id);
// Save hidden categories info to restore after refresh
const hiddenCategories = categories
.filter((c) => c.hidden)
.map((c) => ({
xtreamId: c.xtreamId,
type: c.type,
}));
// Before deleting content, save xtreamIds of favorited and recently viewed items
// so they can be restored after refresh
let favoritedXtreamIds: number[] = [];
@@ -89,11 +102,12 @@ ipcMain.handle(
.delete(schema.categories)
.where(eq(schema.categories.playlistId, playlistId));
// Return the saved xtreamIds so favorites and recently viewed can be restored
// Return the saved xtreamIds so favorites, recently viewed, and hidden categories can be restored
return {
success: true,
favoritedXtreamIds,
recentlyViewedXtreamIds,
hiddenCategories,
};
} catch (error) {
console.error('Error deleting Xtream content:', error);
@@ -98,10 +98,15 @@ export class ElectronXtreamDataSource implements IXtreamDataSource {
);
if (remoteData && Array.isArray(remoteData) && remoteData.length > 0) {
// Check if there are saved hidden categories to restore
const hiddenCategoryXtreamIds =
this.getHiddenCategoryXtreamIds(playlistId, dbType);
await this.dbService.saveXtreamCategories(
playlistId,
remoteData,
dbType
dbType,
hiddenCategoryXtreamIds
);
}
@@ -109,6 +114,40 @@ export class ElectronXtreamDataSource implements IXtreamDataSource {
return this.dbService.getXtreamCategories(playlistId, dbType);
}
/**
* Get hidden category xtreamIds from localStorage for a specific playlist and type
* Used to restore visibility preferences after playlist refresh
*/
private getHiddenCategoryXtreamIds(
playlistId: string,
type: 'live' | 'movies' | 'series'
): number[] | undefined {
const restoreKey = `xtream-restore-${playlistId}`;
const restoreDataStr = localStorage.getItem(restoreKey);
if (!restoreDataStr) {
return undefined;
}
try {
const restoreData = JSON.parse(restoreDataStr);
const hiddenCategories = restoreData.hiddenCategories as
| { xtreamId: number; type: string }[]
| undefined;
if (!hiddenCategories || hiddenCategories.length === 0) {
return undefined;
}
// Filter for the specific type and return xtreamIds
return hiddenCategories
.filter((cat) => cat.type === type)
.map((cat) => cat.xtreamId);
} catch {
return undefined;
}
}
async getAllCategories(
playlistId: string,
type: DbCategoryType
Vendored
+6 -1
View File
@@ -101,6 +101,10 @@ declare global {
xtreamId: number;
viewedAt: string;
}[];
hiddenCategories: {
xtreamId: number;
type: string;
}[];
}>;
dbRestoreXtreamUserData: (
playlistId: string,
@@ -121,7 +125,8 @@ declare global {
dbSaveCategories: (
playlistId: string,
categories: any[],
type: string
type: string,
hiddenCategoryXtreamIds?: number[]
) => Promise<{ success: boolean }>;
dbGetAllCategories: (
playlistId: string,
@@ -68,12 +68,13 @@ export class DatabaseService {
/**
* Delete all content and categories for an Xtream playlist (for refresh)
* Keeps the playlist entry but removes all imported data
* Returns saved favorites and recently viewed xtreamIds for restoration
* Returns saved favorites, recently viewed xtreamIds, and hidden categories for restoration
*/
async deleteXtreamPlaylistContent(playlistId: string): Promise<{
success: boolean;
favoritedXtreamIds: number[];
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[];
hiddenCategories: { xtreamId: number; type: string }[];
}> {
return await window.electron.dbDeleteXtreamContent(playlistId);
}
@@ -160,13 +161,20 @@ export class DatabaseService {
/**
* Save categories in bulk
* Optionally accepts hidden category xtreamIds to restore visibility preferences
*/
async saveXtreamCategories(
playlistId: string,
categories: any[],
type: 'live' | 'movies' | 'series'
type: 'live' | 'movies' | 'series',
hiddenCategoryXtreamIds?: number[]
): Promise<void> {
await window.electron.dbSaveCategories(playlistId, categories, type);
await window.electron.dbSaveCategories(
playlistId,
categories,
type,
hiddenCategoryXtreamIds
);
}
/**
@@ -222,11 +222,14 @@ export class RecentPlaylistsComponent {
onConfirm: async () => {
try {
// Delete all content and categories for this playlist
// This returns the xtreamIds of favorites and recently viewed items
const { favoritedXtreamIds, recentlyViewedXtreamIds } =
await this.databaseService.deleteXtreamPlaylistContent(
item._id
);
// This returns the xtreamIds of favorites, recently viewed items, and hidden categories
const {
favoritedXtreamIds,
recentlyViewedXtreamIds,
hiddenCategories,
} = await this.databaseService.deleteXtreamPlaylistContent(
item._id
);
const updateDate = Date.now();
@@ -250,6 +253,7 @@ export class RecentPlaylistsComponent {
JSON.stringify({
favoritedXtreamIds,
recentlyViewedXtreamIds,
hiddenCategories,
})
);