add watch providers
This commit is contained in:
parent
5fcde524fe
commit
8225d77a99
29
src/App.css
29
src/App.css
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/App.tsx
16
src/App.tsx
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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')
|
|
||||||
console.log(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 {
|
} else {
|
||||||
throw Error("API call failed! Response: " + JSON.stringify(res))
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
</>
|
||||||
|
}
|
Loading…
Reference in New Issue