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.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.settings.model import Movie |
|||
from couchpotato.environment import Env |
|||
from sqlalchemy.sql.expression import or_ |
|||
|
|||
class Suggestion(Plugin): |
|||
|
|||
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 { |
|||
'success': True, |
|||
'empty': len(movies) == 0, |
|||
'total': total_movies, |
|||
'movies': movies, |
|||
'count': len(suggestions), |
|||
'suggestions': suggestions[:limit] |
|||
} |
|||
|
|||
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