mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
new tmdb ratings api
This commit is contained in:
parent
96f79f7c72
commit
e033352752
6 changed files with 207 additions and 171 deletions
|
|
@ -459,7 +459,7 @@
|
|||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app;
|
||||
PRODUCT_NAME = Nuvio;
|
||||
PRODUCT_NAME = "Nuvio";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
|
@ -490,8 +490,8 @@
|
|||
"-lc++",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nuviohub.app;
|
||||
PRODUCT_NAME = Nuvio;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app";
|
||||
PRODUCT_NAME = "Nuvio";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
|
|||
|
|
@ -1,99 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Nuvio</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>nuvio</string>
|
||||
<string>com.nuvio.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>exp+nuvio</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>22</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_http._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your local network</string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
<key>RCTRootViewBackgroundColor</key>
|
||||
<integer>4278322180</integer>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>SplashScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleDefault</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Dark</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Nuvio</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>nuvio</string>
|
||||
<string>com.nuvio.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>exp+nuvio</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>22</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_http._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your local network</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>This app does not require microphone access.</string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
<key>RCTRootViewBackgroundColor</key>
|
||||
<integer>4278322180</integer>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
</array>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>SplashScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleDefault</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Dark</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
src/screens/.ShowRatingsScreen.tsx.swp
Normal file
BIN
src/screens/.ShowRatingsScreen.tsx.swp
Normal file
Binary file not shown.
|
|
@ -28,7 +28,7 @@ if (Platform.OS === 'ios') {
|
|||
liquidGlassAvailable = false;
|
||||
}
|
||||
}
|
||||
import { TMDBService, TMDBShow as Show, TMDBSeason, TMDBEpisode } from '../services/tmdbService';
|
||||
import { TMDBService, TMDBShow as Show, TMDBSeason, TMDBEpisode, IMDbRatings } from '../services/tmdbService';
|
||||
import { RouteProp } from '@react-navigation/native';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import axios from 'axios';
|
||||
|
|
@ -78,17 +78,17 @@ const getRatingColor = (rating: number): string => {
|
|||
};
|
||||
|
||||
// Memoized components
|
||||
const RatingCell = memo(({ episode, ratingSource, getTVMazeRating, isCurrentSeason, theme }: {
|
||||
const RatingCell = memo(({ episode, ratingSource, getTVMazeRating, getIMDbRating, theme }: {
|
||||
episode: TMDBEpisode;
|
||||
ratingSource: RatingSource;
|
||||
getTVMazeRating: (seasonNumber: number, episodeNumber: number) => number | null;
|
||||
isCurrentSeason: (episode: TMDBEpisode) => boolean;
|
||||
getIMDbRating: (seasonNumber: number, episodeNumber: number) => number | null;
|
||||
theme: any;
|
||||
}) => {
|
||||
const getRatingForSource = useCallback((episode: TMDBEpisode): number | null => {
|
||||
switch (ratingSource) {
|
||||
case 'imdb':
|
||||
return episode.imdb_rating || null;
|
||||
return getIMDbRating(episode.season_number, episode.episode_number);
|
||||
case 'tmdb':
|
||||
return episode.vote_average || null;
|
||||
case 'tvmaze':
|
||||
|
|
@ -96,23 +96,25 @@ const RatingCell = memo(({ episode, ratingSource, getTVMazeRating, isCurrentSeas
|
|||
default:
|
||||
return null;
|
||||
}
|
||||
}, [ratingSource, getTVMazeRating]);
|
||||
}, [ratingSource, getTVMazeRating, getIMDbRating]);
|
||||
|
||||
const isRatingPotentiallyInaccurate = useCallback((episode: TMDBEpisode): boolean => {
|
||||
const rating = getRatingForSource(episode);
|
||||
if (!rating) return false;
|
||||
|
||||
if (ratingSource === 'tmdb' && episode.imdb_rating) {
|
||||
const difference = Math.abs(rating - episode.imdb_rating);
|
||||
return difference >= 2;
|
||||
if (ratingSource === 'tmdb') {
|
||||
const imdbRating = getIMDbRating(episode.season_number, episode.episode_number);
|
||||
if (imdbRating) {
|
||||
const difference = Math.abs(rating - imdbRating);
|
||||
return difference >= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [getRatingForSource, ratingSource]);
|
||||
}, [getRatingForSource, ratingSource, getIMDbRating]);
|
||||
|
||||
const rating = getRatingForSource(episode);
|
||||
const isInaccurate = isRatingPotentiallyInaccurate(episode);
|
||||
const isCurrent = isCurrentSeason(episode);
|
||||
|
||||
if (!rating) {
|
||||
if (!episode.air_date || new Date(episode.air_date) > new Date()) {
|
||||
|
|
@ -135,16 +137,15 @@ const RatingCell = memo(({ episode, ratingSource, getTVMazeRating, isCurrentSeas
|
|||
styles.ratingCell,
|
||||
{
|
||||
backgroundColor: getRatingColor(rating),
|
||||
opacity: isCurrent ? 0.7 : 1,
|
||||
}
|
||||
]}>
|
||||
<Text style={styles.ratingText}>{rating.toFixed(1)}</Text>
|
||||
</Animated.View>
|
||||
{(isInaccurate || isCurrent) && (
|
||||
{isInaccurate && (
|
||||
<MaterialIcons
|
||||
name={isCurrent ? "schedule" : "warning"}
|
||||
name="warning"
|
||||
size={12}
|
||||
color={isCurrent ? theme.colors.primary : theme.colors.warning}
|
||||
color={theme.colors.warning}
|
||||
style={styles.warningIcon}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -160,7 +161,7 @@ const RatingSourceToggle = memo(({ ratingSource, setRatingSource, theme }: {
|
|||
<View style={styles.ratingSourceContainer}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.white }]}>Rating Source:</Text>
|
||||
<View style={styles.ratingSourceButtons}>
|
||||
{['imdb', 'tmdb', 'tvmaze'].map((source) => {
|
||||
{['tmdb', 'imdb', 'tvmaze'].map((source) => {
|
||||
const isActive = ratingSource === source;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
|
|
@ -217,10 +218,11 @@ const ShowRatingsScreen = ({ route }: Props) => {
|
|||
const [show, setShow] = useState<Show | null>(null);
|
||||
const [seasons, setSeasons] = useState<TMDBSeason[]>([]);
|
||||
const [tvmazeEpisodes, setTvmazeEpisodes] = useState<TVMazeEpisode[]>([]);
|
||||
const [imdbRatings, setImdbRatings] = useState<IMDbRatings>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loadingSeasons, setLoadingSeasons] = useState(false);
|
||||
const [loadedSeasons, setLoadedSeasons] = useState<number[]>([]);
|
||||
const [ratingSource, setRatingSource] = useState<RatingSource>('tmdb');
|
||||
const [ratingSource, setRatingSource] = useState<RatingSource>('imdb');
|
||||
const [visibleSeasonRange, setVisibleSeasonRange] = useState({ start: 0, end: 8 });
|
||||
const [loadingProgress, setLoadingProgress] = useState(0);
|
||||
const ratingsCache = useRef<{[key: string]: number | null}>({});
|
||||
|
|
@ -316,6 +318,12 @@ const ShowRatingsScreen = ({ route }: Props) => {
|
|||
if (showData) {
|
||||
setShow(showData);
|
||||
|
||||
// Fetch IMDb ratings for all seasons
|
||||
const imdbRatingsData = await tmdb.getIMDbRatings(showId);
|
||||
if (imdbRatingsData) {
|
||||
setImdbRatings(imdbRatingsData);
|
||||
}
|
||||
|
||||
// Get external IDs to fetch TVMaze data
|
||||
const externalIds = await tmdb.getShowExternalIds(showId);
|
||||
if (externalIds?.imdb_id) {
|
||||
|
|
@ -347,19 +355,22 @@ const ShowRatingsScreen = ({ route }: Props) => {
|
|||
return episode?.rating?.average || null;
|
||||
}, [tvmazeEpisodes]);
|
||||
|
||||
const isCurrentSeason = useCallback((episode: TMDBEpisode): boolean => {
|
||||
if (!seasons.length || !episode.air_date) return false;
|
||||
const getIMDbRating = useCallback((seasonNumber: number, episodeNumber: number): number | null => {
|
||||
// Flatten all episodes from all seasons and find the matching one
|
||||
for (const season of imdbRatings) {
|
||||
if (!season.episodes) continue;
|
||||
|
||||
const episode = season.episodes.find(
|
||||
ep => ep.season_number === seasonNumber && ep.episode_number === episodeNumber
|
||||
);
|
||||
|
||||
if (episode) {
|
||||
return episode.vote_average || null;
|
||||
}
|
||||
}
|
||||
|
||||
const latestSeasonNumber = Math.max(...seasons.map(s => s.season_number));
|
||||
if (episode.season_number !== latestSeasonNumber) return false;
|
||||
|
||||
const now = new Date();
|
||||
const airDate = new Date(episode.air_date);
|
||||
const monthsDiff = (now.getFullYear() - airDate.getFullYear()) * 12 +
|
||||
(now.getMonth() - airDate.getMonth());
|
||||
|
||||
return monthsDiff <= 6;
|
||||
}, [seasons]);
|
||||
return null;
|
||||
}, [imdbRatings]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
|
|
@ -459,10 +470,6 @@ const ShowRatingsScreen = ({ route }: Props) => {
|
|||
<MaterialIcons name="warning" size={14} color={colors.warning} />
|
||||
<Text style={[styles.warningText, { color: colors.lightGray }]}>Rating differs significantly from IMDb</Text>
|
||||
</View>
|
||||
<View style={styles.warningLegend}>
|
||||
<MaterialIcons name="schedule" size={14} color={colors.primary} />
|
||||
<Text style={[styles.warningText, { color: colors.lightGray }]}>Current season (ratings may change)</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
|
|
@ -535,7 +542,7 @@ const ShowRatingsScreen = ({ route }: Props) => {
|
|||
episode={season.episodes[episodeIndex]}
|
||||
ratingSource={ratingSource}
|
||||
getTVMazeRating={getTVMazeRating}
|
||||
isCurrentSeason={isCurrentSeason}
|
||||
getIMDbRating={getIMDbRating}
|
||||
theme={currentTheme}
|
||||
/>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,21 @@ export interface TMDBCollectionPart {
|
|||
popularity: number;
|
||||
}
|
||||
|
||||
// Types for IMDb ratings API responses
|
||||
export interface IMDbRatingEpisode {
|
||||
vote_average: number;
|
||||
episode_number: number;
|
||||
name: string;
|
||||
season_number: number;
|
||||
tconst: string;
|
||||
}
|
||||
|
||||
export interface IMDbRatingSeason {
|
||||
episodes: IMDbRatingEpisode[];
|
||||
}
|
||||
|
||||
export type IMDbRatings = IMDbRatingSeason[];
|
||||
|
||||
export class TMDBService {
|
||||
private static instance: TMDBService;
|
||||
private static ratingCache: Map<string, number | null> = new Map();
|
||||
|
|
@ -351,6 +366,7 @@ export class TMDBService {
|
|||
|
||||
/**
|
||||
* Get IMDb rating for an episode using OMDB API with caching
|
||||
* @deprecated This method is deprecated. Use getIMDbRatings instead for better accuracy and performance.
|
||||
*/
|
||||
async getIMDbRating(showName: string, seasonNumber: number, episodeNumber: number): Promise<number | null> {
|
||||
const cacheKey = this.generateRatingCacheKey(showName, seasonNumber, episodeNumber);
|
||||
|
|
@ -387,7 +403,49 @@ export class TMDBService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get season details including all episodes with IMDb ratings
|
||||
* Get IMDb ratings for all seasons and episodes
|
||||
* This replaces the OMDB API approach and provides more accurate ratings
|
||||
*/
|
||||
async getIMDbRatings(tmdbId: number): Promise<IMDbRatings | null> {
|
||||
const IMDB_RATINGS_API_BASE_URL = process.env.EXPO_PUBLIC_IMDB_RATINGS_API_BASE_URL;
|
||||
|
||||
if (!IMDB_RATINGS_API_BASE_URL) {
|
||||
logger.error('[TMDB API] Missing EXPO_PUBLIC_IMDB_RATINGS_API_BASE_URL environment variable');
|
||||
return null;
|
||||
}
|
||||
|
||||
const cacheKey = this.generateCacheKey(`imdb_ratings_${tmdbId}`);
|
||||
|
||||
// Check cache
|
||||
const cached = this.getCachedData<IMDbRatings>(cacheKey);
|
||||
if (cached !== null) return cached;
|
||||
|
||||
const apiUrl = `${IMDB_RATINGS_API_BASE_URL}/api/shows/${tmdbId}/season-ratings`;
|
||||
|
||||
logger.log(`[TMDB API] 🌐 FETCHING: getIMDbRatings(${tmdbId})`);
|
||||
try {
|
||||
const response = await axios.get(apiUrl, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
if (data && Array.isArray(data)) {
|
||||
this.setCachedData(cacheKey, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
logger.error('[TMDB API] Error fetching IMDb ratings:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get season details including all episodes
|
||||
* Note: IMDb ratings are now fetched separately via getIMDbRatings() for better accuracy
|
||||
*/
|
||||
async getSeasonDetails(tmdbId: number, seasonNumber: number, showName?: string, language: string = 'en-US'): Promise<TMDBSeason | null> {
|
||||
const cacheKey = this.generateCacheKey(`tv_${tmdbId}_season_${seasonNumber}`, { language, showName });
|
||||
|
|
@ -405,42 +463,6 @@ export class TMDBService {
|
|||
});
|
||||
|
||||
const season = response.data;
|
||||
|
||||
// If show name is provided, fetch IMDb ratings for each episode in batches
|
||||
if (showName) {
|
||||
// Process episodes in batches of 5 to avoid rate limiting
|
||||
const batchSize = 5;
|
||||
const episodes = [...season.episodes];
|
||||
const episodesWithRatings = [];
|
||||
|
||||
for (let i = 0; i < episodes.length; i += batchSize) {
|
||||
const batch = episodes.slice(i, i + batchSize);
|
||||
const batchPromises = batch.map(async (episode: TMDBEpisode) => {
|
||||
const imdbRating = await this.getIMDbRating(
|
||||
showName,
|
||||
episode.season_number,
|
||||
episode.episode_number
|
||||
);
|
||||
|
||||
return {
|
||||
...episode,
|
||||
imdb_rating: imdbRating
|
||||
};
|
||||
});
|
||||
|
||||
const batchResults = await Promise.all(batchPromises);
|
||||
episodesWithRatings.push(...batchResults);
|
||||
}
|
||||
|
||||
const result = {
|
||||
...season,
|
||||
episodes: episodesWithRatings,
|
||||
};
|
||||
|
||||
this.setCachedData(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
this.setCachedData(cacheKey, season);
|
||||
return season;
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue