add watch providers

This commit is contained in:
andrzej 2024-05-18 13:59:35 +02:00
parent 5fcde524fe
commit 8225d77a99
5 changed files with 139 additions and 28 deletions

View File

@ -52,6 +52,11 @@ main {
font-size: 1.6rem; font-size: 1.6rem;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
h1 { h1 {
font-size: 2em; font-size: 2em;
margin: 0; margin: 0;
@ -134,7 +139,7 @@ main {
#background { #background {
/* background-color: black; */ background-color: black;
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -145,6 +150,24 @@ main {
.CrossfadeImage { .CrossfadeImage {
width: 100%; width: 100%;
height: 100%; height: 100%;
filter: blur(1rem) brightness(0.4);
}
#watch-providers {
display: flex;
h1 {
font-size: 1.6rem;
}
.watch-logos-container {
display: flex;
gap: 0.4rem;
.watch-logo {
width: 30px;
aspect-ratio: 1/1;
}
}
} }

View File

@ -7,11 +7,13 @@ import tmdb from './objects/tmdb'
import { Sidebar } from './objects/sidebar' import { Sidebar } from './objects/sidebar'
import { Movie } from './objects/movie-wall' import { Movie } from './objects/movie-wall'
import CrossfadeImage from 'react-crossfade-image' import CrossfadeImage from 'react-crossfade-image'
import { WhereToWatch } from './objects/whereToWatch'
export type Config = { export type Config = {
language: string, language: string,
region: string, region: string,
page: number, page: number,
locale: string
} }
class MovieClass implements Movie { class MovieClass implements Movie {
id = null id = null
@ -26,13 +28,14 @@ function App() {
const [config, setConfig] = useState<Config>({ const [config, setConfig] = useState<Config>({
language: "es", language: "es",
region: "spain", region: "spain",
page: 1 page: 1,
locale: "ES"
}) })
const [movies, setMovies] = useState([new MovieClass()]) const [movies, setMovies] = useState([new MovieClass()])
const [backdrop, setBackdrop] = useState("") const [backdrop, setBackdrop] = useState("")
const [chosenMovie, setChosenMovie] = useState(new MovieClass()) const [chosenMovie, setChosenMovie] = useState(new MovieClass())
const [similarMoviesAvailable, setSimilarMoviesAvailable] = useState(true) const [similarMoviesAvailable, setSimilarMoviesAvailable] = useState(true)
const [watchProviders, setWatchProviders] = useState({})
useEffect(() => { tmdb.getPopular(config, setMovies) }, []) useEffect(() => { tmdb.getPopular(config, setMovies) }, [])
useEffect(() => { useEffect(() => {
const bgString = chosenMovie.backdrop_path ? const bgString = chosenMovie.backdrop_path ?
@ -40,9 +43,12 @@ function App() {
: tmdb.makeBgImgUrl(movies[0]?.backdrop_path ?? "") : tmdb.makeBgImgUrl(movies[0]?.backdrop_path ?? "")
setBackdrop(bgString) setBackdrop(bgString)
}, [movies]) }, [movies])
useEffect(() => {
tmdb.getWhereToWatch(chosenMovie, setWatchProviders, config)
}, [chosenMovie])
const crossfadeImageStyles = { const crossfadeImageStyles = {
width: "100%", width: "2560px",
minHeight: "100%",
aspectRatio: "16/9" aspectRatio: "16/9"
} }
return ( return (
@ -51,7 +57,7 @@ function App() {
<CrossfadeImage src={backdrop} style={crossfadeImageStyles} /> <CrossfadeImage src={backdrop} style={crossfadeImageStyles} />
</div> </div>
<main > <main >
<Sidebar movie={chosenMovie} similarMoviesAvailable={similarMoviesAvailable} /> <Sidebar movie={chosenMovie} similarMoviesAvailable={similarMoviesAvailable} watchProviders={watchProviders} />
<div id="movie-wall-container"> <div id="movie-wall-container">
<MovieWall movies={movies} <MovieWall movies={movies}
setMovies={setMovies} setMovies={setMovies}

View File

@ -1,11 +1,13 @@
import React from "react"; import React from "react";
import { Movie } from "./movie-wall"; import { Movie } from "./movie-wall";
import tmdb from "./tmdb"; import tmdb from "./tmdb";
import { WhereToWatch } from "./whereToWatch";
export interface SidebarProps extends React.ComponentPropsWithRef<"div"> { export interface SidebarProps extends React.ComponentPropsWithRef<"div"> {
movie: Movie; movie: Movie;
similarMoviesAvailable: boolean; similarMoviesAvailable: boolean;
watchProviders: {};
} }
export function Sidebar({ movie, similarMoviesAvailable }: SidebarProps) { export function Sidebar({ movie, similarMoviesAvailable, watchProviders }: SidebarProps) {
return <div id="sidebar"> return <div id="sidebar">
<h1>{movie?.title ?? "loading"}</h1> <h1>{movie?.title ?? "loading"}</h1>
<figure> <figure>
@ -20,6 +22,7 @@ export function Sidebar({ movie, similarMoviesAvailable }: SidebarProps) {
: movie.overview === "" ? "Resumen no disponible." : movie.overview === "" ? "Resumen no disponible."
: movie.overview} : movie.overview}
</p> </p>
<WhereToWatch watchProviders={watchProviders} />
</div> </div>

View File

@ -56,7 +56,6 @@ export default {
setSimilarMoviesAvailable(true) setSimilarMoviesAvailable(true)
} else { } else {
setSimilarMoviesAvailable(false) setSimilarMoviesAvailable(false)
console.log("SIMILAR NOT AVAILABLE")
} }
return true return true
} else { } else {
@ -64,24 +63,15 @@ export default {
} }
}, },
/** getWhereToWatch: async function(movie: Movie, setWatchProviders: Function, config: Config) {
*Calls TMDB/images, and sets the backdrop state accordingly if (movie?.id) {
* let res = await tmdb.get(movie.id + "/watch/providers")
*/ if (res.status == 200) {
getBackdrop: async function(movie: Movie, setBackdrop: Function) { setWatchProviders(res.data.results[config.locale])
let res = await tmdb.get(movie.id + '/images') } else {
console.log(res) throw Error("API call failed! Response: " + JSON.stringify(res))
if (res.status === 200) { }
const file_path = res.data.backdrops[0].file_path
console.log("file_path:" + file_path)
const imgUrl = this.makeBgImgUrl(file_path)
console.log("imgUrl: " + imgUrl)
setBackdrop(imgUrl)
} else {
throw Error("API call failed! Response: " + JSON.stringify(res))
} }
}, },
makeBgImgUrl: makeBgImgUrl:
/** /**
@ -103,5 +93,8 @@ export default {
*/ */
function(movie: Movie) { function(movie: Movie) {
return "https://www.themoviedb.org/movie/" + movie.id return "https://www.themoviedb.org/movie/" + movie.id
} },
makeLogoPath: function(str: string) {
return "https://image.tmdb.org/t/p/original/" + str
}
} }

View File

@ -0,0 +1,86 @@
import React from "react"
import tmdb from "./tmdb"
interface WhereToWatchProps extends React.ComponentPropsWithRef<"div"> {
watchProviders: {
flatrate: Array<{}>;
rent: Array<{}>;
buy: Array<{}>;
link: string;
};
}
const sampleData = {
link: "https://www.themoviedb.org/movie/872585-oppenheimer/watch?locale=ES",
rent: [{
logo_path: "/7K6rVbpWXB6ByDI0PRzGGRXRBSY.jpg",
provider_id: 149,
provider_name: "Movistar Plus",
display_priority: 12
}],
buy: [{
logo_path: "/9ghgSC0MA082EL6HLCW3GalykFD.jpg",
provider_id: 2,
provider_name: "Apple TV",
display_priority: 4
},
{
logo_path: "/bZvc9dXrXNly7cA0V4D9pR8yJwm.jpg",
provider_id: 35,
provider_name: "Rakuten TV",
display_priority: 13
},
{
logo_path: "/8z7rC8uIDaTM91X0ZfkRf04ydj2.jpg",
provider_id: 3,
provider_name: "Google Play Movies",
display_priority: 15
},
{
logo_path: "/5vfrJQgNe9UnHVgVNAwZTy0Jo9o.jpg",
provider_id: 68,
provider_name: "Microsoft Store",
display_priority: 16
},
{
logo_path: "/seGSXajazLMCKGB5hnRCidtjay1.jpg",
provider_id: 10,
provider_name: "Amazon Video",
display_priority: 36
}],
flatrate: [{
logo_path: "/gQbqEYd0C9uprYxEUqTM589qn8g.jpg",
provider_id: 1773,
provider_name: "SkyShowtime",
display_priority: 9
}]
}
interface ProviderIconsProps extends React.ComponentPropsWithRef<"div"> {
providerList: Array<{}>;
link: string;
}
function ProviderIcons({ providerList, link }: ProviderIconsProps) {
const list = providerList.map((e: any, i: number) => {
return <a href={link}><img src={tmdb.makeLogoPath(e.logo_path)} className="watch-logo" key={e.provider_id + "_" + i} /></a>
})
return <div className="watch-logos-container">
{list}
</div>
}
export function WhereToWatch({ watchProviders }: WhereToWatchProps) {
if (!watchProviders?.link) {
console.group()
console.log("Watch providers (WhereToWatch)")
console.log(watchProviders)
console.groupEnd()
return <div id="no-watch"></div>
}
return <><div id="watch-providers">
{watchProviders?.flatrate?.length > 0 ? <div><h1>Streaming:</h1><ProviderIcons providerList={watchProviders.flatrate} link={watchProviders.link} /></div> : ""}
{watchProviders?.rent?.length > 0 ? <div><h1>Alquiler:</h1><ProviderIcons providerList={watchProviders.rent} link={watchProviders.link} /></div> : ""}
{watchProviders?.buy?.length > 0 ? <div><h1>Comprar:</h1><ProviderIcons providerList={watchProviders.buy} link={watchProviders.link} /></div> : ""}
</div>
<p>Powered by Just Watch.</p>
</>
}