mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-05 01:09:46 +00:00
161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
import { stremioService } from '../stremioService';
|
|
import { mmkvStorage } from '../mmkvStorage';
|
|
import { TMDBService } from '../tmdbService';
|
|
import { logger } from '../../utils/logger';
|
|
|
|
import { convertMetaToStreamingContent, convertMetaToStreamingContentEnhanced } from './content-mappers';
|
|
import { addToRecentContent, createLibraryKey, type CatalogLibraryState } from './library';
|
|
import { DATA_SOURCE_KEY, DataSource, type StreamingContent } from './types';
|
|
|
|
export async function getDataSourcePreference(): Promise<DataSource> {
|
|
try {
|
|
const dataSource = await mmkvStorage.getItem(DATA_SOURCE_KEY);
|
|
return (dataSource as DataSource) || DataSource.STREMIO_ADDONS;
|
|
} catch (error) {
|
|
logger.error('Failed to get data source preference:', error);
|
|
return DataSource.STREMIO_ADDONS;
|
|
}
|
|
}
|
|
|
|
export async function setDataSourcePreference(dataSource: DataSource): Promise<void> {
|
|
try {
|
|
await mmkvStorage.setItem(DATA_SOURCE_KEY, dataSource);
|
|
} catch (error) {
|
|
logger.error('Failed to set data source preference:', error);
|
|
}
|
|
}
|
|
|
|
export async function getContentDetails(
|
|
state: CatalogLibraryState,
|
|
type: string,
|
|
id: string,
|
|
preferredAddonId?: string
|
|
): Promise<StreamingContent | null> {
|
|
try {
|
|
let meta = null;
|
|
let lastError = null;
|
|
|
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
try {
|
|
|
|
// isValidContentId gate removed — getMetaDetails uses addonCanServeId()
|
|
// for per-addon prefix matching, avoiding false negatives for custom ID types.
|
|
meta = await stremioService.getMetaDetails(type, id, preferredAddonId);
|
|
|
|
if (meta) {
|
|
break;
|
|
}
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
|
} catch (error) {
|
|
lastError = error;
|
|
logger.error(`Attempt ${attempt + 1} failed to get content details for ${type}:${id}:`, error);
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
|
}
|
|
}
|
|
|
|
if (meta) {
|
|
const content = convertMetaToStreamingContentEnhanced(meta, state.library);
|
|
addToRecentContent(state, content);
|
|
content.inLibrary = state.library[createLibraryKey(type, id)] !== undefined;
|
|
|
|
return content;
|
|
}
|
|
|
|
if (lastError) {
|
|
throw lastError;
|
|
}
|
|
return null;
|
|
} catch (error) {
|
|
logger.error(`Failed to get content details for ${type}:${id}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function getEnhancedContentDetails(
|
|
state: CatalogLibraryState,
|
|
type: string,
|
|
id: string,
|
|
preferredAddonId?: string
|
|
): Promise<StreamingContent | null> {
|
|
|
|
try {
|
|
const result = await getContentDetails(state, type, id, preferredAddonId);
|
|
return result;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function getBasicContentDetails(
|
|
state: CatalogLibraryState,
|
|
type: string,
|
|
id: string,
|
|
preferredAddonId?: string
|
|
): Promise<StreamingContent | null> {
|
|
try {
|
|
let meta = null;
|
|
let lastError = null;
|
|
|
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
try {
|
|
// isValidContentId gate removed — getMetaDetails uses addonCanServeId()
|
|
// for per-addon prefix matching, avoiding false negatives for custom ID types.
|
|
meta = await stremioService.getMetaDetails(type, id, preferredAddonId);
|
|
if (meta) {
|
|
break;
|
|
}
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
|
} catch (error) {
|
|
lastError = error;
|
|
logger.error(`Attempt ${attempt + 1} failed to get basic content details for ${type}:${id}:`, error);
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
|
}
|
|
}
|
|
|
|
if (meta) {
|
|
const content = convertMetaToStreamingContent(meta, state.library);
|
|
content.inLibrary = state.library[createLibraryKey(type, id)] !== undefined;
|
|
return content;
|
|
}
|
|
|
|
if (lastError) {
|
|
throw lastError;
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
logger.error(`Failed to get basic content details for ${type}:${id}:`, error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function getStremioId(type: string, tmdbId: string): Promise<string | null> {
|
|
try {
|
|
if (type === 'movie') {
|
|
const movieDetails = await TMDBService.getInstance().getMovieDetails(tmdbId);
|
|
|
|
if (movieDetails?.imdb_id) {
|
|
return movieDetails.imdb_id;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (type === 'tv' || type === 'series') {
|
|
const externalIds = await TMDBService.getInstance().getShowExternalIds(parseInt(tmdbId, 10));
|
|
|
|
if (externalIds?.imdb_id) {
|
|
return externalIds.imdb_id;
|
|
}
|
|
|
|
const fallbackId = `kitsu:${tmdbId}`;
|
|
return fallbackId;
|
|
}
|
|
|
|
return null;
|
|
} catch (error: any) {
|
|
logger.error('Error getting Stremio ID:', error);
|
|
return null;
|
|
}
|
|
}
|