mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
Use Map and Set lookups for M3U favorite aggregation, dashboard global favorite mapping, and channel-list favorite/group resolution. Remove the duplicate NgxIndexedDB provider registration and add regression coverage for duplicate URL and earliest-match behavior. Entire-Checkpoint: c2cea9c530e6
105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
import {
|
|
Channel,
|
|
ParsedPlaylist,
|
|
ParsedPlaylistItem,
|
|
Playlist,
|
|
} from 'shared-interfaces';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
/**
|
|
* Aggregates favorite channels as objects from all available playlists
|
|
* @param playlists all available playlists
|
|
* @returns an array with favorite channels from all playlists
|
|
*/
|
|
export function aggregateFavoriteChannels(playlists: Playlist[]): Channel[] {
|
|
const favorites: Channel[] = [];
|
|
|
|
for (const playlist of playlists) {
|
|
const favoriteIds = new Set(
|
|
(playlist.favorites ?? []).filter(
|
|
(favorite): favorite is string => typeof favorite === 'string'
|
|
)
|
|
);
|
|
|
|
if (favoriteIds.size === 0) {
|
|
continue;
|
|
}
|
|
|
|
for (const channel of playlist.playlist?.items ?? []) {
|
|
if (favoriteIds.has(channel.id) || favoriteIds.has(channel.url)) {
|
|
favorites.push(channel);
|
|
}
|
|
}
|
|
}
|
|
|
|
return favorites;
|
|
}
|
|
|
|
/**
|
|
* Creates a simplified playlist object which is used for global favorites
|
|
* @param channels channels list
|
|
* @returns simplified playlist object
|
|
*/
|
|
export function createFavoritesPlaylist(
|
|
channels: Channel[]
|
|
): Partial<Playlist> {
|
|
return {
|
|
_id: 'global-favorites',
|
|
count: channels.length,
|
|
playlist: {
|
|
items: channels,
|
|
},
|
|
favorites: channels.map((channel) => channel.url),
|
|
filename: 'Global favorites',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns last segment (part after last slash "/") of the given URL
|
|
* @param value URL as string
|
|
*/
|
|
export const getFilenameFromUrl = (value: string): string => {
|
|
if (value && value.length > 1) {
|
|
return value.substring(value.lastIndexOf('/') + 1);
|
|
}
|
|
return 'Untitled playlist';
|
|
};
|
|
|
|
/**
|
|
* Creates a playlist object
|
|
* @param name name of the playlist
|
|
* @param playlist playlist to save
|
|
* @param urlOrPath absolute fs path or url of the playlist
|
|
* @param uploadType upload type - by file or via an url
|
|
*/
|
|
export const createPlaylistObject = (
|
|
name: string,
|
|
playlist: ParsedPlaylist,
|
|
urlOrPath?: string,
|
|
uploadType?: 'URL' | 'FILE' | 'TEXT'
|
|
): Playlist => {
|
|
return {
|
|
_id: uuidv4(),
|
|
filename: name,
|
|
title: name,
|
|
count: playlist.items.length,
|
|
playlist: {
|
|
...playlist,
|
|
items: playlist.items.map((item: ParsedPlaylistItem) => ({
|
|
...item,
|
|
id: uuidv4(),
|
|
})),
|
|
},
|
|
importDate: new Date().toISOString(),
|
|
lastUsage: new Date().toISOString(),
|
|
favorites: [],
|
|
autoRefresh: false,
|
|
...(uploadType === 'URL' ? { url: urlOrPath } : {}),
|
|
...(uploadType === 'FILE' ? { filePath: urlOrPath } : {}),
|
|
};
|
|
};
|
|
|
|
export const getExtensionFromUrl = (url: string) => {
|
|
return url.split(/[#?]/)[0].split('.').pop()?.trim();
|
|
};
|