Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Recommended shows version 2 #5782

Merged
merged 86 commits into from
Aug 7, 2021
Merged
Changes from 1 commit
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
06eb0fd
* Cache recommended shows in ShowUpdater
p0psicles Nov 10, 2018
4b42002
Added recommended shows to store.
p0psicles Nov 25, 2018
dfd5058
Added templates.
p0psicles Nov 25, 2018
488f80b
* Fixed getting recommended shows from Imdb
p0psicles Nov 26, 2018
a8b7aec
Removed debuggers.
p0psicles Nov 26, 2018
c5011d9
Implemented external id's for the recommended shows.
p0psicles Nov 26, 2018
7b06255
Changed recommended store.
p0psicles Dec 3, 2018
3c7545d
Created a generic update queue, as a thread that can be used
p0psicles Dec 8, 2018
1992f7d
Added basic functionality of adding a show, from recommended show.
p0psicles Dec 16, 2018
be2680d
Merge remote-tracking branch 'remotes/origin/develop' into feature/re…
p0psicles Dec 16, 2018
4781832
Fix set local vue variable selectedShowOptions from the add-show-opti…
p0psicles Dec 16, 2018
5410a87
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Dec 23, 2018
1152841
Fixed some post merge conflicts.
p0psicles Dec 23, 2018
d1088f4
Fixed some post merge conflicts.
p0psicles Dec 23, 2018
3e95527
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Jan 12, 2019
e5a2483
Implemented isotope sorting.
p0psicles Jan 13, 2019
b3a253f
Add the ability to add a recommended show by multiple indexers.
p0psicles Jan 13, 2019
f51b5ad
Added filter option.
p0psicles Jan 13, 2019
b6458dc
When adding shows, update the mapped_indexer and mapped_series_id in …
p0psicles Jan 13, 2019
9b070ee
Handle exceptions for when there is no connectivity.
p0psicles Jan 13, 2019
087e8ea
Merge remote-tracking branch 'remotes/origin/develop' into feature/re…
p0psicles Sep 25, 2019
9396434
Fixed rebase conflicts.
p0psicles Oct 4, 2019
df7240c
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Jul 9, 2021
b8da32a
Fix after merge conflicts
p0psicles Jul 9, 2021
7160d43
Add recommended.vue to index export
p0psicles Jul 9, 2021
b03e75a
Fix recommended.vue component
p0psicles Jul 10, 2021
a40aa62
Fix adding shows from recommended.vue
p0psicles Jul 10, 2021
b8c957b
mappedIndexer is not used.
p0psicles Jul 10, 2021
17cfb2c
runtime
p0psicles Jul 10, 2021
21bc723
Added field 'added' for adding a date.
p0psicles Jul 11, 2021
63e0c8c
Store recommended lists (subcats) in indexers/config.py
p0psicles Jul 11, 2021
ed8549d
Use indexers/config/indexers.js recommendedLists definition.
p0psicles Jul 11, 2021
64ffcb6
Use subcat, to specify the recommended list.
p0psicles Jul 11, 2021
83d6da3
Separated source and list. For ex. Source = trakt, List = popular.
p0psicles Jul 11, 2021
ccbabd1
Added trakt-authentication.vue component.
p0psicles Jul 13, 2021
f2a51b3
add feature: Route to add-new-show.vue
p0psicles Jul 13, 2021
6f7dd7d
Generate source->categories from recommeded table.
p0psicles Jul 13, 2021
34f6bc2
Added myAnimeList
p0psicles Jul 13, 2021
c2f41a4
Calculate three seasons for myanimelist (-3 months, now and + 3 months.
p0psicles Jul 16, 2021
376e739
Improved styling
p0psicles Jul 16, 2021
45551e3
Added button to start search for now shows, if list is empty.
p0psicles Jul 16, 2021
61a9d7f
Improved error handling / reporting
p0psicles Jul 17, 2021
00e6c18
Improved feedback
p0psicles Jul 17, 2021
1d0092e
Added config option for setting the recommended show update hour.
p0psicles Jul 17, 2021
356bcdd
Added feature to select individual trakt lists for caching.
p0psicles Jul 20, 2021
ad73335
Fix removed_from_medusa function.
p0psicles Jul 21, 2021
f48eaf6
Add the class "removed-from-medusa", but don't use it just yet.
p0psicles Jul 21, 2021
53fe37f
Pass force.
p0psicles Jul 23, 2021
2695972
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Jul 23, 2021
64f0059
imdb: use tmdb api to get tvdb and tmdb id's.
p0psicles Jul 23, 2021
0859b28
Catch connection error utorrent
p0psicles Jul 25, 2021
00b619c
fix linting
p0psicles Jul 25, 2021
e340497
fix lint-css
p0psicles Jul 25, 2021
b5534a9
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Jul 25, 2021
a120781
get genres when possible (not for anidb)
p0psicles Jul 25, 2021
c5e9c6a
Added support for Recommended list source anilist.co
p0psicles Jul 30, 2021
806a3ad
Disable selects until shows loaded.
p0psicles Jul 30, 2021
278bc0e
Adding loading notification
p0psicles Jul 30, 2021
e3493de
Add genres.
p0psicles Jul 30, 2021
c99edd4
also disable list select.
p0psicles Jul 30, 2021
cc5c173
restore check-overlay
p0psicles Jul 30, 2021
19c1d18
Clean up empty genres for anidb.
p0psicles Jul 30, 2021
665c620
Add save button, so you can enable trakt from the component.
p0psicles Aug 3, 2021
a3eeed6
Remove myanimelist references
p0psicles Aug 4, 2021
e1bf0ff
mvt adba
p0psicles Aug 4, 2021
261d70d
Added plot information to recommended shows.
p0psicles Aug 5, 2021
ff484d3
Moved recommended shows to dedicated database.
p0psicles Aug 5, 2021
9b18c3f
one to many underscore
p0psicles Aug 5, 2021
71993f7
fix lint
p0psicles Aug 6, 2021
f637e2c
fix pytest
p0psicles Aug 6, 2021
e514ab8
pylint
p0psicles Aug 6, 2021
fa53e86
Fix lint issue
p0psicles Aug 6, 2021
9708559
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Aug 6, 2021
f9f8f3d
Yarn dev
p0psicles Aug 6, 2021
2b3dd16
Remove unused mako.
p0psicles Aug 6, 2021
c65bdbd
Merge branch 'feature/rec-show-v2' of https://github.com/pymedusa/Med…
p0psicles Aug 6, 2021
b207ff3
Remove more unused mako.
p0psicles Aug 6, 2021
2e9421d
Merge remote-tracking branch 'origin/develop' into feature/rec-show-v2
p0psicles Aug 7, 2021
714c70b
Update changelog
p0psicles Aug 7, 2021
27a6220
update changelog
p0psicles Aug 7, 2021
9a19f1c
build runtime
p0psicles Aug 7, 2021
ce0759a
update changelog
p0psicles Aug 7, 2021
34bd96c
Fix jest tests (snapshots)
p0psicles Aug 7, 2021
6d04afc
Merge branch 'feature/rec-show-v2' of https://github.com/pymedusa/Med…
p0psicles Aug 7, 2021
5567c23
Don't comment, but xit test.
p0psicles Aug 7, 2021
306a5fd
use it.skip in stead
p0psicles Aug 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added filter option.
p0psicles committed Jan 13, 2019
commit f51b5ada01b943b49d7414fb1861ec9c4f6741d7
24 changes: 7 additions & 17 deletions medusa/server/api/v2/recommended.py
Original file line number Diff line number Diff line change
@@ -4,28 +4,14 @@

import logging


from medusa import app
from medusa.indexers.indexer_config import EXTERNAL_IMDB, EXTERNAL_ANIDB, EXTERNAL_TRAKT
from medusa.logger.adapters.style import BraceAdapter
from medusa.server.api.v2.base import (
BaseRequestHandler,
BooleanField,
IntegerField,
ListField,
StringField,
iter_nested_items,
set_nested_value
BaseRequestHandler
)
from medusa.show.recommendations.recommended import get_recommended_shows
from medusa.show.recommendations.anidb import AnidbPopular
from medusa.show.recommendations.imdb import ImdbPopular
from medusa.show.recommendations.trakt import TraktPopular
from simpleanidb import REQUEST_HOT
from medusa.tv.series import Series, SeriesIdentifier

from six import itervalues, viewitems

from tornado.escape import json_decode

log = BraceAdapter(logging.getLogger(__name__))
log.logger.addHandler(logging.NullHandler())
@@ -54,6 +40,10 @@ def http_get(self, identifier, path_param=None):
shows = get_recommended_shows(source=recommended_mappings.get(identifier))

if shows:
data = [show.to_json() for show in shows]
data['shows'] = [show.to_json() for show in shows]

data['trakt'] = {}
data['trakt']['removedFromMedusa'] = TraktPopular().get_removed_from_medusa()
data['trakt']['blacklistEnabled'] = app.TRAKT_BLACKLIST_NAME != ''

return self._ok(data)
3 changes: 3 additions & 0 deletions medusa/show/recommendations/recommended.py
Original file line number Diff line number Diff line change
@@ -248,6 +248,9 @@ def to_json(self):
data['externals'] = self.ids
data['isAnime'] = self.is_anime
data['showInLibrary'] = self.show_in_list
data['trakt'] = {
'blacklisted': False
}

return data

36 changes: 24 additions & 12 deletions medusa/show/recommendations/trakt.py
Original file line number Diff line number Diff line change
@@ -120,6 +120,28 @@ def fetch_and_refresh_token(trakt_api, path):

return library_shows

def get_trakt_api(self):
"""Create trakt api."""
# Create a trakt settings dict
trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
'trakt_api_key': app.TRAKT_API_KEY,
'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN}

return TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings)

def get_removed_from_medusa(self, trakt_api=None):
"""Retrieve trakt watched shows, check if there are shows in the list that are not in medusa's library."""
trakt_api = trakt_api or self.get_trakt_api()
library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \
self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full')

medusa_shows = [show.indexerid for show in app.showList if show.indexerid]
return [
lshow['show']['ids']['tvdb'] for lshow in library_shows if
lshow['show']['ids']['tvdb'] not in medusa_shows
]

def fetch_popular_shows(self, page_url=None, trakt_list=None):
"""Get a list of popular shows from different Trakt lists based on a provided trakt_list.

@@ -131,23 +153,13 @@ def fetch_popular_shows(self, page_url=None, trakt_list=None):
trending_shows = []
removed_from_medusa = []

# Create a trakt settings dict
trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
'trakt_api_key': app.TRAKT_API_KEY,
'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN}

trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings)
trakt_api = self.get_trakt_api()

try:
not_liked_show = ''
if app.TRAKT_ACCESS_TOKEN != '':
library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \
self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full')

medusa_shows = [show.indexerid for show in app.showList if show.indexerid]
removed_from_medusa = [lshow['show']['ids']['tvdb'] for lshow in library_shows if lshow['show']['ids']['tvdb'] not in medusa_shows]

removed_from_medusa = self.get_removed_from_medusa(trakt_api)
if app.TRAKT_BLACKLIST_NAME is not None and app.TRAKT_BLACKLIST_NAME:
not_liked_show = trakt_api.request('users/' + app.TRAKT_USERNAME + '/lists/' +
app.TRAKT_BLACKLIST_NAME + '/items') or []
12 changes: 9 additions & 3 deletions themes-default/slim/src/store/modules/recommended.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@ import { api } from '../../api';
import { ADD_RECOMMENDED_SHOW } from '../mutation-types';

const state = {
shows: []
shows: [],
trakt: {
removedFromMedusa: [],
blacklistEnabled: false
}
};

const mutations = {
@@ -48,8 +52,10 @@ const actions = {

identifier = identifier ? identifier : '';
return api.get('/recommended/' + identifier, { params }).then(res => {
const shows = res.data;
return shows.forEach(show => {
const { data } = res;
state.trakt.removedFromMedusa = data.trakt.removedFromMedusa;
state.trakt.blacklistEnabled = data.trakt.blacklistEnabled;
return data.shows.forEach(show => {
commit(ADD_RECOMMENDED_SHOW, show);
});
});
74 changes: 56 additions & 18 deletions themes-default/slim/views/addShows_recommended_vue.mako
Original file line number Diff line number Diff line change
@@ -26,12 +26,15 @@ window.app = new Vue({
{ text: 'Ascending', value: 'asc'},
{ text: 'Descending', value: 'desc'},
]
const filterShows = '';
return {
externals,
sortOptions,
sortDirectionOptions,
sortOptionsValue: 'original',
sortDirectionOptionsValue: 'desc',
filterOption: null,
filterShows,
configLoaded: false,
rootDirs: [],
enableShowOptions: false,
@@ -59,20 +62,29 @@ window.app = new Vue({
],
selectedList: 11,
shows: [],

// trakt thing
removedFromMedusa: [],
trakt: {
removedFromMedusa: [],
blacklistEnabled: []
},

// Isotope stuff
selected: null,
option: {
getSortData: {
id: 'seriesId',
title: function(itemElem) {
title: itemElem => {
return itemElem.title.toLowerCase();
},
rating: 'rating',
votes: 'votes'
},
getFilterData: {
filterByText: itemElem => {
return itemElem.title.toLowerCase().includes(this.filterShows.toLowerCase());
}
},
sortBy : 'votes',
layoutMode: 'fitRows',
sortAscending: false
@@ -330,10 +342,13 @@ window.app = new Vue({
// The real vue stuff
// This is used to wait for the config to be loaded by the store.
this.$once('loaded', () => {
const { stateShows, shows } = this;
const { stateShows, stateTrakt, shows } = this;
const { blacklistEnabled, removedFromMedusa } = stateTrakt;

// Map the state values to local data.
this.shows = stateShows;
this.trakt.blacklistEnabled = blacklistEnabled;
this.trakt.removedFromMedusa = removedFromMedusa;
this.configLoaded = true;
});

@@ -342,9 +357,13 @@ window.app = new Vue({
computed: {
stateShows() {
const { $store } = this;
// @omg, I need to use recommended.recommended here, but don't know why?
return $store.state.recommended.shows;
},
stateTrakt() {
const { $store } = this;
return $store.state.recommended.trakt;
},

filteredShowsByList() {
const { shows, selectedList, imgLazyLoad } = this;

@@ -363,12 +382,11 @@ window.app = new Vue({
methods: {
changeRecommendedList() {
const { $store, shows } = this;

},
containerClass(show) {
let classes = 'recommended-container default-poster show-row';
const { removedFromMedusa } = this;
if (show.showInLibrary || removedFromMedusa.includes(show.mappedSeriesId)) {
const { removedFromMedusa } = this.trakt;
if (show.showInLibrary) {
classes += ' show-in-list';
}
return classes;
@@ -440,14 +458,23 @@ window.app = new Vue({
this.option.sortBy = mapped[sortOptionsValue];
this.$refs.filteredShows.arrange(isotopeOptions);
},
filter: function(key) {
const { option: isotopeOptions } = this;
if (this.filterOption == key) {
key = null;
}
// this.$refs.filteredShows.arrange(isotopeOptions);
this.$refs.filteredShows.filter(key);
this.filterOption = key;
},
sortDirection() {
const { option: isotopeOptions, sortDirectionOptionsValue } = this;
this.option.sortAscending = sortDirectionOptionsValue === 'asc';
this.$refs.filteredShows.arrange(isotopeOptions);
},
addByExternalIndexer(show) {
const { externals } = show;
if (show.source === 11) {
if (show.isAnime) {
return [{text: 'Tvdb', value: 'tvdb_id'}]
}

@@ -460,6 +487,11 @@ window.app = new Vue({
}

return options;
},
blacklistTrakt(show) {
debugger;
show.trakt.blacklisted = true;
apiRoute('addShows/addShowToBlacklist?seriesid=' + show.externals.tvdb_id);
}
}
});
@@ -500,6 +532,12 @@ window.app = new Vue({
<option v-for="option in sortDirectionOptions" :value="option.value">{{option.text}}</option>
</select>
</div>

<div class="show-option">
<span style="margin-left:12px">Filter:</span>
<input type="text" v-model="filterShows" placeholder="no filter" class="form-control form-control-inline input-sm" @input="filter('filterByText')">
</div>

</div>
</div> <!-- row -->

@@ -556,23 +594,23 @@ window.app = new Vue({
<app-link :href="'home/displayShow?indexername=' + show.mappedIndexerName + '&seriesid=' + show.mappedSeriesId">In List</app-link>
</button>

<button v-if="removedFromMedusa.includes(show.mappedSeriesId)" class="btn-medusa btn-xs">
<button v-if="trakt.removedFromMedusa.includes(show.mappedSeriesId)" class="btn-medusa btn-xs">
<app-link :href="'home/displayShow?indexername=' + show.mappedIndexerName + '&seriesid=' + show.mappedSeriesId">Watched</app-link>
</button>
<!-- if trakt_b and not (cur_show.show_in_list or cur_show.mapped_series_id in removed_from_medusa): -->
<button v-if="show.source === externals.TRAKT" :data-indexer-id="show.mappedSeriesId" class="btn-medusa btn-xs" data-blacklist-show>Blacklist</button>
<button :disabled="show.trakt.blacklisted" v-if="show.source === externals.TRAKT" :data-indexer-id="show.mappedSeriesId" class="btn-medusa btn-xs" @click="blacklistTrakt(show)">Blacklist</button>
</div>
</div>
</div>
<div class="row" v-if="!show.showInLibrary">
<div class="col-md-12" name="addshowoptions">
<select :ref="String(show.source) + '-' + String(show.seriesId)" name="addshow" class="rec-show-select">
<option v-for="option in addByExternalIndexer(show)" :value="option.value">{{option.text}}</option>
</select>
<button class="btn-medusa btn-xs rec-show-button" @click="addShowById(show, String(show.source) + '-' + String(show.seriesId))">
Add
</button>
</div>
<div class="col-md-12" name="addshowoptions">
<select :ref="String(show.source) + '-' + String(show.seriesId)" name="addshow" class="rec-show-select">
<option v-for="option in addByExternalIndexer(show)" :value="option.value">{{option.text}}</option>
</select>
<button :disabled="show.trakt.blacklisted" class="btn-medusa btn-xs rec-show-button" @click="addShowById(show, String(show.source) + '-' + String(show.seriesId))">
Add
</button>
</div>
</div>
</div>
</isotope>
2 changes: 1 addition & 1 deletion themes/dark/assets/js/medusa-runtime.js
74 changes: 56 additions & 18 deletions themes/dark/templates/addShows_recommended_vue.mako

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion themes/light/assets/js/medusa-runtime.js
74 changes: 56 additions & 18 deletions themes/light/templates/addShows_recommended_vue.mako

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.