11 changed files with 341 additions and 100 deletions
@ -1,20 +1,91 @@ |
|||||
|
from couchpotato import get_session |
||||
from couchpotato.api import addApiView |
from couchpotato.api import addApiView |
||||
from couchpotato.core.event import fireEvent |
from couchpotato.core.event import fireEvent |
||||
|
from couchpotato.core.helpers.encoding import ss |
||||
|
from couchpotato.core.helpers.variable import splitString, md5 |
||||
from couchpotato.core.plugins.base import Plugin |
from couchpotato.core.plugins.base import Plugin |
||||
|
from couchpotato.core.settings.model import Movie |
||||
|
from couchpotato.environment import Env |
||||
|
from sqlalchemy.sql.expression import or_ |
||||
|
|
||||
class Suggestion(Plugin): |
class Suggestion(Plugin): |
||||
|
|
||||
def __init__(self): |
def __init__(self): |
||||
|
|
||||
addApiView('suggestion.view', self.getView) |
addApiView('suggestion.view', self.suggestView) |
||||
|
addApiView('suggestion.ignore', self.ignoreView) |
||||
|
|
||||
def getView(self, limit_offset = None, **kwargs): |
def suggestView(self, **kwargs): |
||||
|
|
||||
total_movies, movies = fireEvent('movie.list', status = 'suggest', limit_offset = limit_offset, single = True) |
movies = splitString(kwargs.get('movies', '')) |
||||
|
ignored = splitString(kwargs.get('ignored', '')) |
||||
|
limit = kwargs.get('limit', 6) |
||||
|
|
||||
|
if not movies or len(movies) == 0: |
||||
|
db = get_session() |
||||
|
active_movies = db.query(Movie) \ |
||||
|
.filter(or_(*[Movie.status.has(identifier = s) for s in ['active', 'done']])).all() |
||||
|
movies = [x.library.identifier for x in active_movies] |
||||
|
|
||||
|
if not ignored or len(ignored) == 0: |
||||
|
ignored = splitString(Env.prop('suggest_ignore', default = '')) |
||||
|
|
||||
|
cached_suggestion = self.getCache('suggestion_cached') |
||||
|
if cached_suggestion: |
||||
|
suggestions = cached_suggestion |
||||
|
else: |
||||
|
suggestions = fireEvent('movie.suggest', movies = movies, ignore = ignored, single = True) |
||||
|
self.setCache(md5(ss('suggestion_cached')), suggestions, timeout = 6048000) # Cache for 10 weeks |
||||
|
|
||||
return { |
return { |
||||
'success': True, |
'success': True, |
||||
'empty': len(movies) == 0, |
'count': len(suggestions), |
||||
'total': total_movies, |
'suggestions': suggestions[:limit] |
||||
'movies': movies, |
} |
||||
|
|
||||
|
def ignoreView(self, imdb = None, limit = 6, remove_only = False, **kwargs): |
||||
|
|
||||
|
ignored = splitString(Env.prop('suggest_ignore', default = '')) |
||||
|
|
||||
|
if imdb: |
||||
|
if not remove_only: |
||||
|
ignored.append(imdb) |
||||
|
Env.prop('suggest_ignore', ','.join(set(ignored))) |
||||
|
|
||||
|
new_suggestions = self.updateSuggestionCache(ignore_imdb = imdb, limit = limit, ignored = ignored) |
||||
|
|
||||
|
return { |
||||
|
'result': True, |
||||
|
'ignore_count': len(ignored), |
||||
|
'suggestions': new_suggestions[limit - 1:limit] |
||||
} |
} |
||||
|
|
||||
|
def updateSuggestionCache(self, ignore_imdb = None, limit = 6, ignored = None): |
||||
|
|
||||
|
# Combine with previous suggestion_cache |
||||
|
cached_suggestion = self.getCache('suggestion_cached') |
||||
|
new_suggestions = [] |
||||
|
|
||||
|
if ignore_imdb: |
||||
|
for cs in cached_suggestion: |
||||
|
if cs.get('imdb') != ignore_imdb: |
||||
|
new_suggestions.append(cs) |
||||
|
|
||||
|
# Get new results and add them |
||||
|
if len(new_suggestions) - 1 < limit: |
||||
|
|
||||
|
db = get_session() |
||||
|
active_movies = db.query(Movie).filter(Movie.status.has(identifier = 'active')).all() |
||||
|
movies = [x.library.identifier for x in active_movies] |
||||
|
|
||||
|
#if ignored: |
||||
|
# ignored.extend([x.get('imdb') for x in new_suggestions]) |
||||
|
|
||||
|
suggestions = fireEvent('movie.suggest', movies = movies, ignore = list(set(ignored)), single = True) |
||||
|
|
||||
|
if suggestions: |
||||
|
new_suggestions.extend(suggestions) |
||||
|
|
||||
|
self.setCache(md5(ss('suggestion_cached')), new_suggestions, timeout = 6048000) |
||||
|
|
||||
|
return new_suggestions |
||||
|
@ -0,0 +1,84 @@ |
|||||
|
.suggestions { |
||||
|
} |
||||
|
|
||||
|
.suggestions > h2 { |
||||
|
height: 40px; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result { |
||||
|
display: inline-block; |
||||
|
width: 33.333%; |
||||
|
height: 150px; |
||||
|
} |
||||
|
|
||||
|
@media all and (max-width: 960px) { |
||||
|
.suggestions .movie_result { |
||||
|
width: 50%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media all and (max-width: 600px) { |
||||
|
.suggestions .movie_result { |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .data { |
||||
|
left: 100px; |
||||
|
background: #4e5969; |
||||
|
border: none; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .data .info { |
||||
|
top: 15px; |
||||
|
left: 15px; |
||||
|
right: 15px; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .data .info h2 { |
||||
|
white-space: normal; |
||||
|
max-height: 120px; |
||||
|
font-size: 18px; |
||||
|
line-height: 18px; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .data .info .year { |
||||
|
position: static; |
||||
|
display: block; |
||||
|
margin: 5px 0 0; |
||||
|
padding: 0; |
||||
|
opacity: .6; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .data { |
||||
|
cursor: default; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .options { |
||||
|
left: 100px; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .thumbnail { |
||||
|
width: 100px; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .actions { |
||||
|
position: absolute; |
||||
|
bottom: 10px; |
||||
|
right: 10px; |
||||
|
display: none; |
||||
|
width: 120px; |
||||
|
} |
||||
|
.suggestions .movie_result:hover .actions { |
||||
|
display: block; |
||||
|
} |
||||
|
.suggestions .movie_result .data.open .actions { |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.suggestions .movie_result .actions a { |
||||
|
margin-left: 10px; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,102 @@ |
|||||
|
var SuggestList = new Class({ |
||||
|
|
||||
|
Implements: [Options, Events], |
||||
|
|
||||
|
initialize: function(options){ |
||||
|
var self = this; |
||||
|
self.setOptions(options); |
||||
|
|
||||
|
self.create(); |
||||
|
}, |
||||
|
|
||||
|
create: function(){ |
||||
|
var self = this; |
||||
|
|
||||
|
self.el = new Element('div.suggestions', { |
||||
|
'events': { |
||||
|
'click:relay(a.delete)': function(e, el){ |
||||
|
(e).stop(); |
||||
|
|
||||
|
$(el).getParent('.movie_result').destroy(); |
||||
|
|
||||
|
Api.request('suggestion.ignore', { |
||||
|
'data': { |
||||
|
'imdb': el.get('data-ignore') |
||||
|
}, |
||||
|
'onComplete': self.fill.bind(self) |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
}).grab( |
||||
|
new Element('h2', { |
||||
|
'text': 'You might like these' |
||||
|
}) |
||||
|
); |
||||
|
|
||||
|
self.api_request = Api.request('suggestion.view', { |
||||
|
'onComplete': self.fill.bind(self) |
||||
|
}); |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
fill: function(json){ |
||||
|
|
||||
|
var self = this; |
||||
|
|
||||
|
Object.each(json.suggestions, function(movie){ |
||||
|
|
||||
|
var m = new Block.Search.Item(movie, { |
||||
|
'onAdded': function(){ |
||||
|
self.afterAdded(m, movie) |
||||
|
} |
||||
|
}); |
||||
|
m.data_container.grab( |
||||
|
new Element('div.actions').adopt( |
||||
|
new Element('a.add.icon2', { |
||||
|
'title': 'Add movie with your default quality', |
||||
|
'data-add': movie.imdb, |
||||
|
'events': { |
||||
|
'click': m.showOptions.bind(m) |
||||
|
} |
||||
|
}), |
||||
|
$(new MA.IMDB(m)), |
||||
|
$(new MA.Trailer(m, { |
||||
|
'height': 150 |
||||
|
})), |
||||
|
new Element('a.delete.icon2', { |
||||
|
'title': 'Don\'t suggest this movie again', |
||||
|
'data-ignore': movie.imdb |
||||
|
}) |
||||
|
) |
||||
|
); |
||||
|
m.data_container.removeEvents('click'); |
||||
|
$(m).inject(self.el); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
afterAdded: function(m, movie){ |
||||
|
var self = this; |
||||
|
|
||||
|
setTimeout(function(){ |
||||
|
$(m).destroy(); |
||||
|
|
||||
|
Api.request('suggestion.ignore', { |
||||
|
'data': { |
||||
|
'imdb': movie.imdb, |
||||
|
'remove_only': true |
||||
|
}, |
||||
|
'onComplete': self.fill.bind(self) |
||||
|
}); |
||||
|
|
||||
|
}, 3000); |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
toElement: function(){ |
||||
|
return this.el; |
||||
|
} |
||||
|
|
||||
|
}) |
Loading…
Reference in new issue