From eb7f5c88bf2fc3c1d13305246bb926e072ac5a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Tue, 31 Jan 2017 17:08:09 +0100 Subject: [PATCH 1/5] Fix mobile list view --- src/public/js/components/list/posters.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/public/js/components/list/posters.js b/src/public/js/components/list/posters.js index f8d4db1..bb80d20 100644 --- a/src/public/js/components/list/posters.js +++ b/src/public/js/components/list/posters.js @@ -65,6 +65,7 @@ export default class ListPosters extends React.Component { {elmts.map(function(el, index) { const selected = (el.imdb_id === this.props.selectedImdbId) ? true : false; From dcde20f170bc39a79d6773a607335938d14d7ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Tue, 31 Jan 2017 20:43:41 +0100 Subject: [PATCH 2/5] Add button to refresh the show details --- src/public/js/actions/actionCreators.js | 7 +++++++ src/public/js/components/shows/list.js | 2 ++ src/public/js/components/shows/listButtons.js | 9 ++++++++- src/public/js/reducers/shows.js | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/public/js/actions/actionCreators.js b/src/public/js/actions/actionCreators.js index 1f4591d..3200f63 100644 --- a/src/public/js/actions/actionCreators.js +++ b/src/public/js/actions/actionCreators.js @@ -181,6 +181,13 @@ export function searchShows(search) { ) } +export function getShowDetails(imdbId) { + return request( + 'SHOW_GET_DETAILS', + configureAxios().post(`/shows/${imdbId}/refresh`) + ) +} + export function fetchShowDetails(imdbId) { return request( 'SHOW_FETCH_DETAILS', diff --git a/src/public/js/components/shows/list.js b/src/public/js/components/shows/list.js index 3704260..dce38bb 100644 --- a/src/public/js/components/shows/list.js +++ b/src/public/js/components/shows/list.js @@ -58,6 +58,8 @@ export default class ShowList extends React.Component { show={selectedShow} deleteFromWishlist={this.props.deleteShowFromWishlist} addToWishlist={this.props.addShowToWishlist} + getDetails={this.props.getShowDetails} + fetching={this.props.showStore.getDetails} /> } diff --git a/src/public/js/components/shows/listButtons.js b/src/public/js/components/shows/listButtons.js index d7baed3..34ec5ed 100644 --- a/src/public/js/components/shows/listButtons.js +++ b/src/public/js/components/shows/listButtons.js @@ -3,7 +3,7 @@ import React from 'react' import { Link } from 'react-router' import { DropdownButton } from 'react-bootstrap' -import { WishlistButton } from '../buttons/actions' +import { WishlistButton, RefreshButton } from '../buttons/actions' export default function ShowButtons(props) { const imdbLink = `http://www.imdb.com/title/${props.show.imdb_id}`; @@ -13,6 +13,8 @@ export default function ShowButtons(props) { show={props.show} addToWishlist={props.addToWishlist} deleteFromWishlist={props.deleteFromWishlist} + getDetails={props.getDetails} + fetching={props.fetching} /> IMDB @@ -28,6 +30,11 @@ function ActionsButton(props) { let wishlisted = (props.show.tracked_season !== null && props.show.tracked_episode !== null); return ( + el.imdb_id).indexOf(data.imdb_id); + shows[index] = data; + return shows +} From 425bfdc8d38500fcbfe34f3a0bcc33ffdb08c681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Wed, 1 Feb 2017 13:29:15 +0100 Subject: [PATCH 3/5] Add button to get episode details / torrents --- src/public/js/actions/actionCreators.js | 19 ++++++++++ src/public/js/components/shows/details.js | 44 +++++++++++++++++++++++ src/public/js/reducers/shows.js | 19 ++++++++++ 3 files changed, 82 insertions(+) diff --git a/src/public/js/actions/actionCreators.js b/src/public/js/actions/actionCreators.js index 3200f63..0ef97ca 100644 --- a/src/public/js/actions/actionCreators.js +++ b/src/public/js/actions/actionCreators.js @@ -188,6 +188,25 @@ export function getShowDetails(imdbId) { ) } + +export function getEpisodeDetails(imdbId, season, episode) { + return request( + 'EPISODE_GET_DETAILS', + configureAxios().post(`/shows/${imdbId}/seasons/${season}/episodes/${episode}`), + ) +} + +export function updateEpisodeDetailsStore(imdbId, season, episode) { + return { + type: 'EPISODE_GET_DETAILS', + payload: { + imdbId, + season, + episode, + }, + } +} + export function fetchShowDetails(imdbId) { return request( 'SHOW_FETCH_DETAILS', diff --git a/src/public/js/components/shows/details.js b/src/public/js/components/shows/details.js index 3a125dd..e011a88 100644 --- a/src/public/js/components/shows/details.js +++ b/src/public/js/components/shows/details.js @@ -23,6 +23,8 @@ export default class ShowDetails extends React.Component { data={this.props.showStore.show} addTorrent={this.props.addTorrent} addToWishlist={this.props.addShowToWishlist} + getEpisodeDetails={this.props.getEpisodeDetails} + updateEpisodeDetailsStore={this.props.updateEpisodeDetailsStore} /> ); @@ -94,6 +96,8 @@ function SeasonsList(props){ data={season} addTorrent={props.addTorrent} addToWishlist={props.addToWishlist} + getEpisodeDetails={props.getEpisodeDetails} + updateEpisodeDetailsStore={props.updateEpisodeDetailsStore} /> ) @@ -138,6 +142,8 @@ class Season extends React.Component { data={episode} addTorrent={this.props.addTorrent} addToWishlist={this.props.addToWishlist} + getEpisodeDetails={this.props.getEpisodeDetails} + updateEpisodeDetailsStore={this.props.updateEpisodeDetailsStore} /> ) }, this)} @@ -173,6 +179,11 @@ function Episode(props) { ) })} + @@ -297,3 +308,36 @@ function DownloadButton(props) { ); } + +class GetDetailsButton extends React.Component { + constructor(props) { + super(props); + this.handleClick = this.handleClick.bind(this); + } + handleClick(e, url) { + e.preventDefault(); + if (this.props.data.fetching) { + return + } + this.props.updateEpisodeDetailsStore(this.props.data.show_imdb_id, this.props.data.season, this.props.data.episode); + this.props.getEpisodeDetails(this.props.data.show_imdb_id, this.props.data.season, this.props.data.episode); + } + render() { + return ( + + this.handleClick(e)}> + {this.props.data.fetching || + + Refresh + + } + {this.props.data.fetching && + + Refreshing + + } + + + ); + } +} diff --git a/src/public/js/reducers/shows.js b/src/public/js/reducers/shows.js index c50c774..f817644 100644 --- a/src/public/js/reducers/shows.js +++ b/src/public/js/reducers/shows.js @@ -46,6 +46,14 @@ export default function showStore(state = defaultState, action) { show: sortEpisodes(action.payload.data), loading: false, }) + case 'EPISODE_GET_DETAILS': + return Object.assign({}, state, { + show: updateEpisode(Object.assign({}, state.show), true, action.payload), + }) + case 'EPISODE_GET_DETAILS_FULFILLED': + return Object.assign({}, state, { + show: updateEpisode(Object.assign({}, state.show), false, action.payload.data), + }) case 'SEARCH_SHOWS_PENDING': return Object.assign({}, state, { loading: true, @@ -74,6 +82,16 @@ export default function showStore(state = defaultState, action) { } } +function updateEpisode(show, fetching, data) { + let seasonIndex = show.seasons.map((el) => el.season).indexOf(data.season.toString()); + let episodeIndex = show.seasons[seasonIndex].episodes.map((el) => el.episode).indexOf(data.episode); + if ('id' in data) { + show.seasons[seasonIndex].episodes[episodeIndex] = data; + } + show.seasons[seasonIndex].episodes[episodeIndex].fetching = fetching; + return show +} + function sortEpisodes(show) { let episodes = show.episodes; delete show["episodes"]; @@ -85,6 +103,7 @@ function sortEpisodes(show) { // Extract the seasons let seasons = {}; for (let ep of episodes) { + ep.fetching = false; if (!seasons[ep.season]) { seasons[ep.season] = { episodes: [] }; } From 7fe76d6433f4f013b5821fff4fc512dcb030b1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Wed, 1 Feb 2017 13:58:40 +0100 Subject: [PATCH 4/5] Don't return an error if no torrents are found for an episode --- src/internal/shows/handlers.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/internal/shows/handlers.go b/src/internal/shows/handlers.go index df156c9..56f5909 100644 --- a/src/internal/shows/handlers.go +++ b/src/internal/shows/handlers.go @@ -10,6 +10,7 @@ import ( "strconv" "github.com/gorilla/mux" + customError "github.com/odwrtw/errors" "github.com/odwrtw/papi" polochon "github.com/odwrtw/polochon/lib" "github.com/odwrtw/polochon/modules/pam" @@ -311,7 +312,8 @@ func EpisodeDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request, return env.RenderError(w, err) } - if err := e.GetTorrents(env, force); err != nil { + err = e.GetTorrents(env, force) + if err != nil && customError.IsFatal(err) { return env.RenderError(w, err) } From a6052828ab7389a6eb7c01b99ea4c0bfe8a1635c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Wed, 1 Feb 2017 14:35:42 +0100 Subject: [PATCH 5/5] Add error handling to disable episode refresh icon --- src/public/js/reducers/shows.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/public/js/reducers/shows.js b/src/public/js/reducers/shows.js index f817644..3349b09 100644 --- a/src/public/js/reducers/shows.js +++ b/src/public/js/reducers/shows.js @@ -82,7 +82,17 @@ export default function showStore(state = defaultState, action) { } } -function updateEpisode(show, fetching, data) { +function updateEpisode(show, fetching, data = null) { + // Error handling for PouuleT + if (data === null) { + for (let seasonIndex of Object.keys(show.seasons)) { + for (let episodeIndex of Object.keys(show.seasons[seasonIndex].episodes)) { + show.seasons[seasonIndex].episodes[episodeIndex].fetching = false; + } + } + return show + } + let seasonIndex = show.seasons.map((el) => el.season).indexOf(data.season.toString()); let episodeIndex = show.seasons[seasonIndex].episodes.map((el) => el.episode).indexOf(data.episode); if ('id' in data) {