Skip to content

Commit

Permalink
feat: Added getShowRecommendations and refactored getShow so it can a…
Browse files Browse the repository at this point in the history
…lso retrieve with tmdb id
  • Loading branch information
TriPSs committed Dec 5, 2018
1 parent cb1aa68 commit 5fac116
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 37 deletions.
62 changes: 59 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,71 @@ $ npm install --save popcorn-sdk
import SDK from 'popcorn-sdk'

const movies = await SDK.getMovies()
const movie = await SDK.getMovie(imdbId)
const movie = await SDK.getMovie({ ids: { imdb: '' } })

const shows = await SDK.getShows()
const show = await SDK.getShow(imdbId)
const show = await SDK.getShow({ ids: { imdb: '', tmdb: '' }}) // One of the two, imdb is preferred

// Or for slower internet connections you can partial load a show
const showBasic = await SDK.getBasicShow(imdbId)

// getShowMeta retrieves data from The Movie DB for better episode info and season / episode images
const showWithMeta = await SDK.getShowMeta(showBasic)
// Basically runs getShowIds and getShowSeasonsMeta
const showWithMeta = await SDK.getShowMeta(showBasic)

// To only retrieve the ids for a show
const showWithIds = await SDK.getShowIds({ids: { imdb: '', tmdb: '' }})

// To only retrieve the seasons meta
const showWithSeasons = await SDK.getShowSeasonsMeta(showBasic)

// To retrieve recommendations for a certain show
const recommendations = await SDK.getShowRecommendations({ ids: { tmdb: '' } })
```

### Adapters
You can add adapters handy for if you want to add attributes to movies / shows
```js
import SDK from 'popcorn-sdk'
import DefaultAdapter from 'popcorn-sdk/Adapter'

class MyAdapter extends DefaultAdapter {

/**
* Get's called after the movies are fetched and before they are returned
*
* @param movies
* @returns {*}
*/
checkMovies = movies => movies

/**
* Get's called after the movie is fetched and before they it is returned
*
* @param movie
* @returns {*}
*/
checkMovie = movie => movie

/**
* Get's called after the shows are fetched and before they are returned
*
* @param shows
* @returns {*}
*/
checkShows = shows => shows

/**
* Get's called after the show is fetched and before they it is returned
*
* @param show
* @returns {*}
*/
checkShow = show => show
}

SDK.addAdapter(new MyAdapter())

```

### Movie output
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "popcorn-sdk",
"version": "2.0.2",
"version": "3.0.0",
"description": "Popcorn SDK",
"keywords": [
"popcorn",
Expand Down
24 changes: 24 additions & 0 deletions src/Adapter/Adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,36 @@
*/
export default class Adapter {

/**
* Get's called after the movies are fetched and before they are returned
*
* @param movies
* @returns {*}
*/
checkMovies = movies => movies

/**
* Get's called after the movie is fetched and before they it is returned
*
* @param movie
* @returns {*}
*/
checkMovie = movie => movie

/**
* Get's called after the shows are fetched and before they are returned
*
* @param shows
* @returns {*}
*/
checkShows = shows => shows

/**
* Get's called after the show is fetched and before they it is returned
*
* @param show
* @returns {*}
*/
checkShow = show => show

}
26 changes: 20 additions & 6 deletions src/MetadataAdapter/MetadataAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,25 @@ export default class MetadataAdapter {
this.tmdbProvider = new TmdbMetadataProvider()
}

getSeasons = (itemId, pctSeasons) => new Promise((resolve) => {
this.traktProvider.getIds(itemId).then(({ ids: { tmdb } }) => (
this.tmdbProvider.getSeasons(itemId, tmdb, pctSeasons).then(resolve)
),
)
})
/**
* Adds trailer and ids to the show
*
* @param item
* @returns {*}
*/
getShowIds = item => {
if (item.id || item.ids.imdb) {
return this.traktProvider.getShowByItem(item)

} else if (item.ids.tmdb) {
return this.traktProvider.searchShowByTmdb(item)
}

throw Error('No id to use to retrieve show with!')
}

getAdditionalShowSeasonsMeta = item => this.tmdbProvider.getSeasons(item)

getShowRecommendations = (...args) => this.tmdbProvider.getTvRecommendations(...args)

}
59 changes: 44 additions & 15 deletions src/MetadataAdapter/TmdbMetadataProvider/TmdbMetadataProvider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import axios from 'axios'
import * as Constants from '../../constants'
import * as PctHelpers from '../../PctAdapter/PctHelpers'
import formatImage from '../../utils/formatImage'

export default class TmdbMetadataProvider {
Expand All @@ -20,46 +22,73 @@ export default class TmdbMetadataProvider {
})
}

getSeasons = (itemId, tmdbId, pctSeasons) =>
this.tmdb.get(`tv/${tmdbId}`)
.then(({ data }) => this.formatSeasons(data.seasons, pctSeasons, itemId, tmdbId))
getSeasons = (item) => (
this.tmdb.get(`tv/${item.ids.tmdb}`)
.then(({ data }) => this.formatSeasons(data.seasons, item))
)

getTvRecommendations = (item) => (
this.tmdb.get(`tv/${item.ids.tmdb}/recommendations`)
.then(({ data }) => this.formatShow(data.results))
)

formatShow = shows => (
shows.map(show => ({
id : null,
ids : {
tmdb: show.id,
},
title : show.original_name,
year : null,
images : formatImage({
poster: this.imageUri + show.poster_path,
fanart: this.imageUri + show.backdrop_path,
}),
rating : PctHelpers.formatRating({ percentage: show.vote_average }),
seasons : [],
numSeasons: null,
type : Constants.TYPE_SHOW,
watched : {
complete: false,
progress: 0,
},
}))
)

formatSeasons = (seasons, pctSeasons, itemId, tmdbId, watchedEpisodes) => Promise.all(
formatSeasons = (seasons, item) => Promise.all(
seasons.filter(({ season_number, episode_count }) =>
season_number !== 0 && // Remove all specials
season_number !== 0 && // Remove all specials
episode_count > 0, // Remove all seasons that are not aired and don't have episodes
).map(season =>
this.getSeasonAndEpisodes(
season.season_number,
tmdbId,
pctSeasons.find(pctSeason => pctSeason.number === season.season_number),
itemId,
watchedEpisodes,
item.seasons.find(pctSeason => pctSeason.number === season.season_number),
item,
),
),
)

getSeasonAndEpisodes = (seasonNr, tmdbId, pctSeason, itemId) => (
this.tmdb.get(`tv/${tmdbId}/season/${seasonNr}`).then(({ data }) => ({
getSeasonAndEpisodes = (seasonNr, pctSeason, item) => (
this.tmdb.get(`tv/${item.ids.tmdb}/season/${seasonNr}`).then(({ data }) => ({
...pctSeason,
title : data.name,
summary : data.overview,
episodes: this.formatEpisodes(pctSeason, data.episodes, itemId),
showId : itemId,
episodes: this.formatEpisodes(pctSeason, data.episodes, item),
showId : item.id,
season : data.season_number,
number : data.season_number,
images : formatImage({ poster: this.imageUri + data.poster_path }),
}))
)

formatEpisodes = (pctSeason, episodes, itemId) => episodes.map((episode) => {
formatEpisodes = (pctSeason, episodes, item) => episodes.map((episode) => {
const pctEpisode = this.getPctEpisodeFromPctSeason(pctSeason, episode.episode_number)

return {
...pctEpisode,
key : `${episode.season_number}-${episode.episode_number}`,
id : episode.id,
showId : itemId,
showId : item.id,
title : episode.name,
summary : episode.overview,
number : episode.episode_number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@ export default class TraktMetadataAdapter {
})
}

getIds = itemId => this.trakt.get(`shows/${itemId}`).then(({ data }) => data)
getShowByItem = item => (
this.trakt.get(`shows/${item.id || item.ids.imdb}`, { params: { extended: 'full' } })
.then(({ data }) => this.formatShow(item, data))
)

searchShowByTmdb = item => (
this.trakt.get(`search/tmdb/${item.ids.tmdb}`, { params: { type: 'show', extended: 'full' } })
.then(({ data }) => {
if (data.length > 0) {
return this.formatShow(item, data[0].show)
}

throw Error(`TraktMetadataAdapter: No show found with tmdb id ${item.ids.tmdb}`)
})
)

formatShow = (show, traktShow) => ({
...show,
id : traktShow.ids.imdb,
ids : traktShow.ids,
trailer: traktShow.trailer,
})

}
4 changes: 4 additions & 0 deletions src/PctAdapter/PctAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export default class PctAdapter {
formatShow = (show, isDetail = false) => {
let formattedShow = {
id : show.imdb_id,
ids : {
imdb: show.imdb_id,
tmdb: null,
},
title : show.title,
year : show.year,
images : formatImage(show.images),
Expand Down
49 changes: 38 additions & 11 deletions src/SDK.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,60 @@ export default new (class SDK {
.then(this.checkAdapters('checkMovies'))
)

getMovie = (itemId) => (
this.pctAdapter.getMovie(itemId)
.then(this.checkAdapters('checkMovie'))
)
getMovie = (item) => {
if (!item.ids || !item.ids.imdb) {
throw Error(`"ids.imdb" is required to retrieve a movie!`)
}

return (
this.pctAdapter.getMovie(item.ids.imdb)
.then(this.checkAdapters('checkMovie'))
)
}

getShows = (page = 1, filters = {}) => (
this.pctAdapter.getShows(page, filters)
.then(this.checkAdapters('checkShows'))
)

getShow = (itemId) => (
this.getShowBasic(itemId)
.then(this.getShowMeta)
)
getShow = async(item) => {
if (item.ids.imdb) {
return this.getShowBasic(item.ids.imdb)
.then(this.getShowMeta)

} else if (item.ids.tmdb) {
// If we don't have the IMDB id but we have TMDB id we need a additional call

const veryBasicShow = await this.metadataAdapter.getShowIds(item)
const pctShow = await this.getShowBasic(veryBasicShow)

getShowBasic = itemId => (
this.pctAdapter.getShow(itemId)
return this.getShowSeasonsMeta({
...pctShow,
...veryBasicShow,
})
}
}

getShowBasic = imdbID => (
this.pctAdapter.getShow(imdbID)
.then(this.checkAdapters('checkShow'))
)

getShowMeta = pctShow => this.metadataAdapter
.getSeasons(pctShow.id, pctShow.seasons)
.getShowIds(pctShow)
.then(this.getShowSeasonsMeta)

getShowIds = pctShow => this.metadataAdapter.getShowIds(pctShow)

getShowSeasonsMeta = pctShow => this.metadataAdapter
.getAdditionalShowSeasonsMeta(pctShow)
.then(seasons => ({
...pctShow,
seasons,
}))

getShowRecommendations = (...args) => this.metadataAdapter.getShowRecommendations(...args)

checkAdapters = (method) => async(items) => {
for (let i = 0; i < this.adapters.length; i++) {
items = await this.adapters[i][method](items)
Expand Down

0 comments on commit 5fac116

Please sign in to comment.