mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
460 lines
12 KiB
TypeScript
460 lines
12 KiB
TypeScript
/**
|
|
* Database service for Electron renderer process
|
|
* Communicates with the main process database via IPC
|
|
*/
|
|
|
|
import { Injectable } from '@angular/core';
|
|
import { PlaylistMeta } from 'shared-interfaces';
|
|
|
|
export interface XCategoryFromDb {
|
|
id: number;
|
|
name: string;
|
|
playlist_id: string;
|
|
type: 'movies' | 'live' | 'series';
|
|
xtream_id: number;
|
|
hidden: boolean;
|
|
}
|
|
|
|
export interface XtreamContent {
|
|
id: number;
|
|
category_id: number;
|
|
title: string;
|
|
rating: string;
|
|
added: string;
|
|
poster_url: string;
|
|
xtream_id: number;
|
|
type: string;
|
|
added_at?: string;
|
|
viewed_at?: string;
|
|
}
|
|
|
|
export interface XtreamPlaylist {
|
|
id: string;
|
|
name: string;
|
|
serverUrl: string;
|
|
username: string;
|
|
password: string;
|
|
type: string;
|
|
}
|
|
|
|
export interface GlobalSearchResult extends XtreamContent {
|
|
playlist_id: string;
|
|
playlist_name: string;
|
|
}
|
|
|
|
export interface GlobalRecentItem extends XtreamContent {
|
|
playlist_id: string;
|
|
playlist_name: string;
|
|
viewed_at: string;
|
|
}
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
export class DatabaseService {
|
|
/**
|
|
* Delete a playlist and all its related data
|
|
*/
|
|
async deletePlaylist(playlistId: string): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbDeletePlaylist(playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error deleting playlist:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all content and categories for an Xtream playlist (for refresh)
|
|
* Keeps the playlist entry but removes all imported data
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* Restore favorites and recently viewed items after Xtream refresh
|
|
*/
|
|
async restoreXtreamUserData(
|
|
playlistId: string,
|
|
favoritedXtreamIds: number[],
|
|
recentlyViewedXtreamIds: { xtreamId: number; viewedAt: string }[]
|
|
): Promise<void> {
|
|
await window.electron.dbRestoreXtreamUserData(
|
|
playlistId,
|
|
favoritedXtreamIds,
|
|
recentlyViewedXtreamIds
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Update playlist basic info
|
|
*/
|
|
async updateXtreamPlaylist(playlist: any): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbUpdatePlaylist(playlist.id, {
|
|
name: playlist.name,
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error updating playlist:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update playlist details including credentials
|
|
*/
|
|
async updateXtreamPlaylistDetails(playlist: {
|
|
id: string;
|
|
title?: string;
|
|
username?: string;
|
|
password?: string;
|
|
serverUrl?: string;
|
|
updateDate?: number;
|
|
}): Promise<boolean> {
|
|
try {
|
|
const updates: any = {};
|
|
if (playlist.title) updates.name = playlist.title;
|
|
if (playlist.username) updates.username = playlist.username;
|
|
if (playlist.password) updates.password = playlist.password;
|
|
if (playlist.serverUrl) updates.serverUrl = playlist.serverUrl;
|
|
if (playlist.updateDate !== undefined)
|
|
updates.lastUpdated = new Date(
|
|
playlist.updateDate
|
|
).toISOString();
|
|
|
|
await window.electron.dbUpdatePlaylist(playlist.id, updates);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error updating playlist details:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if categories exist
|
|
*/
|
|
async hasXtreamCategories(
|
|
playlistId: string,
|
|
type: 'live' | 'movies' | 'series'
|
|
): Promise<boolean> {
|
|
return await window.electron.dbHasCategories(playlistId, type);
|
|
}
|
|
|
|
/**
|
|
* Get categories for a playlist
|
|
*/
|
|
async getXtreamCategories(
|
|
playlistId: string,
|
|
type: 'live' | 'movies' | 'series'
|
|
): Promise<XCategoryFromDb[]> {
|
|
return await window.electron.dbGetCategories(playlistId, type);
|
|
}
|
|
|
|
/**
|
|
* Save categories in bulk
|
|
* Optionally accepts hidden category xtreamIds to restore visibility preferences
|
|
*/
|
|
async saveXtreamCategories(
|
|
playlistId: string,
|
|
categories: any[],
|
|
type: 'live' | 'movies' | 'series',
|
|
hiddenCategoryXtreamIds?: number[]
|
|
): Promise<void> {
|
|
await window.electron.dbSaveCategories(
|
|
playlistId,
|
|
categories,
|
|
type,
|
|
hiddenCategoryXtreamIds
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get all categories for a playlist (including hidden, for management dialog)
|
|
*/
|
|
async getAllXtreamCategories(
|
|
playlistId: string,
|
|
type: 'live' | 'movies' | 'series'
|
|
): Promise<XCategoryFromDb[]> {
|
|
return await window.electron.dbGetAllCategories(playlistId, type);
|
|
}
|
|
|
|
/**
|
|
* Update category visibility (show/hide categories)
|
|
*/
|
|
async updateCategoryVisibility(
|
|
categoryIds: number[],
|
|
hidden: boolean
|
|
): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbUpdateCategoryVisibility(
|
|
categoryIds,
|
|
hidden
|
|
);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error updating category visibility:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if content exists
|
|
*/
|
|
async hasXtreamContent(
|
|
playlistId: string,
|
|
type: 'live' | 'movie' | 'series'
|
|
): Promise<boolean> {
|
|
return await window.electron.dbHasContent(playlistId, type);
|
|
}
|
|
|
|
/**
|
|
* Get content for a playlist
|
|
*/
|
|
async getXtreamContent(
|
|
playlistId: string,
|
|
type: 'live' | 'movie' | 'series'
|
|
): Promise<XtreamContent[]> {
|
|
return await window.electron.dbGetContent(playlistId, type);
|
|
}
|
|
|
|
/**
|
|
* Save content in bulk
|
|
*/
|
|
async saveXtreamContent(
|
|
playlistId: string,
|
|
streams: any[],
|
|
type: 'live' | 'movie' | 'series',
|
|
onProgress?: (count: number) => void
|
|
): Promise<number> {
|
|
// Setup progress listener if callback provided
|
|
if (onProgress) {
|
|
window.electron.onDbSaveContentProgress(onProgress);
|
|
}
|
|
|
|
try {
|
|
const result = await window.electron.dbSaveContent(
|
|
playlistId,
|
|
streams,
|
|
type
|
|
);
|
|
return result.count;
|
|
} finally {
|
|
// Clean up the listener
|
|
if (onProgress) {
|
|
window.electron.removeDbSaveContentProgress();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Search content within a playlist
|
|
*/
|
|
async searchXtreamContent(
|
|
playlistId: string,
|
|
searchTerm: string,
|
|
types: string[]
|
|
): Promise<XtreamContent[]> {
|
|
return await window.electron.dbSearchContent(
|
|
playlistId,
|
|
searchTerm,
|
|
types
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Global search across all playlists
|
|
*/
|
|
async globalSearchContent(
|
|
searchTerm: string,
|
|
types: string[]
|
|
): Promise<GlobalSearchResult[]> {
|
|
return await window.electron.dbGlobalSearch(searchTerm, types);
|
|
}
|
|
|
|
/**
|
|
* Get recently viewed items
|
|
*/
|
|
async getGlobalRecentlyViewed(): Promise<GlobalRecentItem[]> {
|
|
try {
|
|
const items = await window.electron.dbGetRecentlyViewed();
|
|
return items || [];
|
|
} catch (error) {
|
|
console.error('Error getting recently viewed:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear recently viewed items
|
|
*/
|
|
async clearGlobalRecentlyViewed(): Promise<void> {
|
|
try {
|
|
await window.electron.dbClearRecentlyViewed();
|
|
} catch (error) {
|
|
console.error('Error clearing recently viewed:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get playlist by ID
|
|
*/
|
|
async getPlaylistById(playlistId: string): Promise<XtreamPlaylist | null> {
|
|
return await window.electron.dbGetPlaylist(playlistId);
|
|
}
|
|
|
|
/**
|
|
* Create a new playlist
|
|
*/
|
|
async createPlaylist(playlist: PlaylistMeta): Promise<void> {
|
|
await window.electron.dbCreatePlaylist({
|
|
id: playlist._id,
|
|
name: playlist.title,
|
|
serverUrl: playlist.serverUrl,
|
|
username: playlist.username,
|
|
password: playlist.password,
|
|
type: 'xtream',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add content to favorites
|
|
*/
|
|
async addToFavorites(
|
|
contentId: number,
|
|
playlistId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbAddFavorite(contentId, playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error adding to favorites:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove content from favorites
|
|
*/
|
|
async removeFromFavorites(
|
|
contentId: number,
|
|
playlistId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbRemoveFavorite(contentId, playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error removing from favorites:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if content is favorited
|
|
*/
|
|
async isFavorite(contentId: number, playlistId: string): Promise<boolean> {
|
|
try {
|
|
return await window.electron.dbIsFavorite(contentId, playlistId);
|
|
} catch (error) {
|
|
console.error('Error checking favorite:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all favorites for a playlist
|
|
*/
|
|
async getFavorites(playlistId: string): Promise<XtreamContent[]> {
|
|
try {
|
|
return await window.electron.dbGetFavorites(playlistId);
|
|
} catch (error) {
|
|
console.error('Error getting favorites:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get recently viewed items for a specific playlist
|
|
*/
|
|
async getRecentItems(playlistId: string): Promise<XtreamContent[]> {
|
|
try {
|
|
return await window.electron.dbGetRecentItems(playlistId);
|
|
} catch (error) {
|
|
console.error('Error getting recent items:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add item to recently viewed
|
|
*/
|
|
async addRecentItem(
|
|
contentId: number,
|
|
playlistId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbAddRecentItem(contentId, playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error adding recent item:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear recently viewed for a specific playlist
|
|
*/
|
|
async clearPlaylistRecentItems(playlistId: string): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbClearPlaylistRecentItems(playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error clearing playlist recent items:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove specific item from recently viewed
|
|
*/
|
|
async removeRecentItem(
|
|
contentId: number,
|
|
playlistId: string
|
|
): Promise<boolean> {
|
|
try {
|
|
await window.electron.dbRemoveRecentItem(contentId, playlistId);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error removing recent item:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get content by xtream ID
|
|
*/
|
|
async getContentByXtreamId(
|
|
xtreamId: number,
|
|
playlistId: string
|
|
): Promise<XtreamContent | null> {
|
|
try {
|
|
return await window.electron.dbGetContentByXtreamId(
|
|
xtreamId,
|
|
playlistId
|
|
);
|
|
} catch (error) {
|
|
console.error('Error getting content by xtream ID:', error);
|
|
return null;
|
|
}
|
|
}
|
|
}
|