pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

use trakt lists for some genres and providers

Pas 6adfe7ed 33d6daba

+159 -23
+1 -1
src/backend/metadata/traktApi.ts
··· 110 110 "10": "prime", // Prime Video 111 111 "15": "hulu", // Hulu 112 112 "337": "disney", // Disney+ 113 - "384": "hbo", // HBO Max/Max 113 + "1899": "hbo", // Max 114 114 } as const; 115 115 116 116 // Map genres to their Trakt endpoints
+1 -1
src/pages/discover/MoreContent.tsx
··· 184 184 <div className="animate-pulse"> 185 185 <div className="h-8 bg-mediaCard-hoverBackground rounded w-1/4 mb-8" /> 186 186 <MediaGrid> 187 - {Array.from({ length: 20 }).map((_, i) => ( 187 + {Array.from({ length: 20 }).map((_, _i) => ( 188 188 <div 189 189 key={`loading-skeleton-${Math.random().toString(36).substring(7)}`} 190 190 className="relative group cursor-default user-select-none rounded-xl p-2 bg-transparent"
+157 -21
src/pages/discover/hooks/useDiscoverMedia.ts
··· 3 3 4 4 import { get } from "@/backend/metadata/tmdb"; 5 5 import { 6 + GENRE_TO_TRAKT_MAP, 7 + PROVIDER_TO_TRAKT_MAP, 6 8 TraktLatestResponse, 9 + getActionReleases, 10 + getAppleTVReleases, 11 + getDisneyReleases, 12 + getDramaReleases, 13 + getHBOReleases, 14 + getHuluReleases, 7 15 getLatest4KReleases, 8 16 getLatestReleases, 17 + getNetflixMovies, 18 + getNetflixTVShows, 19 + getPrimeReleases, 9 20 paginateResults, 10 21 } from "@/backend/metadata/traktApi"; 11 22 import { conf } from "@/setup/config"; ··· 360 371 [mediaType, formattedLanguage, page], 361 372 ); 362 373 374 + // Get Trakt function for provider 375 + const getTraktProviderFunction = useCallback( 376 + (providerId: string) => { 377 + const trakt = 378 + PROVIDER_TO_TRAKT_MAP[providerId as keyof typeof PROVIDER_TO_TRAKT_MAP]; 379 + if (!trakt) return null; 380 + 381 + // Handle TV vs Movies for Netflix 382 + if (trakt === "netflix" && mediaType === "tv") { 383 + return getNetflixTVShows; 384 + } 385 + if (trakt === "netflix" && mediaType === "movie") { 386 + return getNetflixMovies; 387 + } 388 + 389 + // Map provider to corresponding Trakt function 390 + switch (trakt) { 391 + case "appletv": 392 + return getAppleTVReleases; 393 + case "prime": 394 + return getPrimeReleases; 395 + case "hulu": 396 + return getHuluReleases; 397 + case "disney": 398 + return getDisneyReleases; 399 + case "hbo": 400 + return getHBOReleases; 401 + default: 402 + return null; 403 + } 404 + }, 405 + [mediaType], 406 + ); 407 + 408 + // Get Trakt function for genre 409 + const getTraktGenreFunction = useCallback((genreId: string) => { 410 + const trakt = 411 + GENRE_TO_TRAKT_MAP[genreId as keyof typeof GENRE_TO_TRAKT_MAP]; 412 + if (!trakt) return null; 413 + 414 + switch (trakt) { 415 + case "action": 416 + return getActionReleases; 417 + case "drama": 418 + return getDramaReleases; 419 + default: 420 + return null; 421 + } 422 + }, []); 423 + 363 424 const fetchEditorPicks = useCallback(async () => { 364 425 const picks = 365 426 mediaType === "movie" ? EDITOR_PICKS_MOVIES : EDITOR_PICKS_TV_SHOWS; ··· 395 456 396 457 const attemptFetch = async (type: DiscoverContentType) => { 397 458 let data; 459 + let traktGenreFunction; 460 + let traktProviderFunction; 398 461 399 462 // Map content types to their endpoints and handling logic 400 463 switch (type) { ··· 438 501 439 502 case "genre": 440 503 if (!id) throw new Error("Genre ID is required"); 441 - data = await fetchTMDBMedia(`/discover/${mediaType}`, { 442 - with_genres: id, 443 - }); 444 - setSectionTitle( 445 - mediaType === "movie" 446 - ? t("discover.carousel.title.movies", { category: genreName }) 447 - : t("discover.carousel.title.tvshows", { category: genreName }), 448 - ); 504 + 505 + // Try to use Trakt genre endpoint if available 506 + traktGenreFunction = getTraktGenreFunction(id); 507 + if (traktGenreFunction) { 508 + try { 509 + data = await fetchTraktMedia(traktGenreFunction); 510 + setSectionTitle( 511 + mediaType === "movie" 512 + ? t("discover.carousel.title.movies", { category: genreName }) 513 + : t("discover.carousel.title.tvshows", { 514 + category: genreName, 515 + }), 516 + ); 517 + } catch (traktErr) { 518 + console.error( 519 + "Trakt genre fetch failed, falling back to TMDB:", 520 + traktErr, 521 + ); 522 + // Fall back to TMDB 523 + data = await fetchTMDBMedia(`/discover/${mediaType}`, { 524 + with_genres: id, 525 + }); 526 + setSectionTitle( 527 + mediaType === "movie" 528 + ? t("discover.carousel.title.movies", { category: genreName }) 529 + : t("discover.carousel.title.tvshows", { 530 + category: genreName, 531 + }), 532 + ); 533 + } 534 + } else { 535 + // Use TMDB if no Trakt endpoint exists for this genre 536 + data = await fetchTMDBMedia(`/discover/${mediaType}`, { 537 + with_genres: id, 538 + }); 539 + setSectionTitle( 540 + mediaType === "movie" 541 + ? t("discover.carousel.title.movies", { category: genreName }) 542 + : t("discover.carousel.title.tvshows", { category: genreName }), 543 + ); 544 + } 449 545 break; 450 546 451 547 case "provider": 452 548 if (!id) throw new Error("Provider ID is required"); 453 - data = await fetchTMDBMedia(`/discover/${mediaType}`, { 454 - with_watch_providers: id, 455 - watch_region: "US", 456 - }); 457 - setSectionTitle( 458 - mediaType === "movie" 459 - ? t("discover.carousel.title.moviesOn", { 460 - provider: providerName, 461 - }) 462 - : t("discover.carousel.title.tvshowsOn", { 463 - provider: providerName, 464 - }), 465 - ); 549 + 550 + // Try to use Trakt provider endpoint if available 551 + traktProviderFunction = getTraktProviderFunction(id); 552 + if (traktProviderFunction) { 553 + try { 554 + data = await fetchTraktMedia(traktProviderFunction); 555 + setSectionTitle( 556 + mediaType === "movie" 557 + ? t("discover.carousel.title.moviesOn", { 558 + provider: providerName, 559 + }) 560 + : t("discover.carousel.title.tvshowsOn", { 561 + provider: providerName, 562 + }), 563 + ); 564 + } catch (traktErr) { 565 + console.error( 566 + "Trakt provider fetch failed, falling back to TMDB:", 567 + traktErr, 568 + ); 569 + // Fall back to TMDB 570 + data = await fetchTMDBMedia(`/discover/${mediaType}`, { 571 + with_watch_providers: id, 572 + watch_region: "US", 573 + }); 574 + setSectionTitle( 575 + mediaType === "movie" 576 + ? t("discover.carousel.title.moviesOn", { 577 + provider: providerName, 578 + }) 579 + : t("discover.carousel.title.tvshowsOn", { 580 + provider: providerName, 581 + }), 582 + ); 583 + } 584 + } else { 585 + // Use TMDB if no Trakt endpoint exists for this provider 586 + data = await fetchTMDBMedia(`/discover/${mediaType}`, { 587 + with_watch_providers: id, 588 + watch_region: "US", 589 + }); 590 + setSectionTitle( 591 + mediaType === "movie" 592 + ? t("discover.carousel.title.moviesOn", { 593 + provider: providerName, 594 + }) 595 + : t("discover.carousel.title.tvshowsOn", { 596 + provider: providerName, 597 + }), 598 + ); 599 + } 466 600 break; 467 601 468 602 case "recommendations": ··· 534 668 fetchEditorPicks, 535 669 t, 536 670 page, 671 + getTraktGenreFunction, 672 + getTraktProviderFunction, 537 673 ]); 538 674 539 675 useEffect(() => {