10 changed files with 719 additions and 5 deletions
@ -0,0 +1,34 @@ |
|||
from .main import Charts |
|||
|
|||
|
|||
def autoload(): |
|||
return Charts() |
|||
|
|||
|
|||
config = [{ |
|||
'name': 'charts', |
|||
'groups': [ |
|||
{ |
|||
'label': 'Charts', |
|||
'description': 'Displays selected charts on the home page', |
|||
'type': 'list', |
|||
'name': 'charts_providers', |
|||
'tab': 'display', |
|||
'options': [ |
|||
{ |
|||
'name': 'max_items', |
|||
'default': 5, |
|||
'type': 'int', |
|||
'description': 'Maximum number of items displayed from each chart.', |
|||
}, |
|||
{ |
|||
'name': 'update_interval', |
|||
'default': 12, |
|||
'type': 'int', |
|||
'advanced': True, |
|||
'description': '(hours)', |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}] |
@ -0,0 +1,60 @@ |
|||
import time |
|||
|
|||
from couchpotato import tryInt |
|||
from couchpotato.core.logger import CPLog |
|||
from couchpotato.api import addApiView |
|||
from couchpotato.core.event import addEvent,fireEvent |
|||
from couchpotato.core.plugins.base import Plugin |
|||
|
|||
|
|||
log = CPLog(__name__) |
|||
|
|||
|
|||
class Charts(Plugin): |
|||
|
|||
update_in_progress = False |
|||
|
|||
def __init__(self): |
|||
addApiView('charts.view', self.automationView) |
|||
addEvent('app.load', self.setCrons) |
|||
|
|||
def setCrons(self): |
|||
fireEvent('schedule.interval', 'charts.update_cache', self.updateViewCache, hours = self.conf('update_interval', default = 12)) |
|||
self.updateViewCache() |
|||
|
|||
|
|||
def automationView(self, force_update = False, **kwargs): |
|||
|
|||
if force_update: |
|||
charts = self.updateViewCache() |
|||
else: |
|||
charts = self.getCache('charts_cached') |
|||
if not charts: |
|||
charts = self.updateViewCache() |
|||
|
|||
return { |
|||
'success': True, |
|||
'count': len(charts), |
|||
'charts': charts |
|||
} |
|||
|
|||
|
|||
def updateViewCache(self): |
|||
|
|||
if self.update_in_progress: |
|||
while self.update_in_progress: |
|||
time.sleep(1) |
|||
catched_charts = self.getCache('charts_cached') |
|||
if catched_charts: |
|||
return catched_charts |
|||
|
|||
try: |
|||
self.update_in_progress = True |
|||
charts = fireEvent('automation.get_chart_list', merge = True) |
|||
self.setCache('charts_cached', charts, timeout = 7200 * tryInt(self.conf('update_interval', default = 12))) |
|||
except: |
|||
log.error('Failed refreshing charts') |
|||
|
|||
self.update_in_progress = False |
|||
|
|||
return charts |
@ -0,0 +1,240 @@ |
|||
.charts { |
|||
clear: both; |
|||
} |
|||
|
|||
.charts > h2 { |
|||
height: 40px; |
|||
} |
|||
|
|||
.charts .chart { |
|||
display: inline-block; |
|||
width: 50%; |
|||
vertical-align: top; |
|||
} |
|||
|
|||
.charts div.refresh { |
|||
margin-top: 10px; |
|||
clear:both; |
|||
text-align:center; |
|||
} |
|||
|
|||
.charts p.no_charts_enabled { |
|||
padding: 0.7em 1em; |
|||
} |
|||
|
|||
.charts div.refresh a { |
|||
display:block; |
|||
} |
|||
|
|||
.charts .chart h3 a { |
|||
color: #fff; |
|||
} |
|||
|
|||
|
|||
.charts .chart .media_result { |
|||
display: inline-block; |
|||
width: 100%; |
|||
height: 150px; |
|||
} |
|||
|
|||
@media all and (max-width: 960px) { |
|||
.charts .chart { |
|||
width: 50%; |
|||
} |
|||
} |
|||
|
|||
@media all and (max-width: 600px) { |
|||
.charts .chart { |
|||
width: 100%; |
|||
} |
|||
} |
|||
|
|||
.charts .chart .media_result .data { |
|||
left: 150px; |
|||
background: #4e5969; |
|||
border: none; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info { |
|||
top: 10px; |
|||
left: 15px; |
|||
right: 15px; |
|||
bottom: 10px; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info h2 { |
|||
white-space: normal; |
|||
max-height: 120px; |
|||
font-size: 18px; |
|||
line-height: 18px; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .rating, |
|||
.charts .chart .media_result .data .info .genres, |
|||
.charts .chart .media_result .data .info .year { |
|||
position: static; |
|||
display: block; |
|||
padding: 0; |
|||
opacity: .6; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .year { |
|||
margin: 10px 0 0; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .rating { |
|||
font-size: 20px; |
|||
float: right; |
|||
margin-top: -20px; |
|||
} |
|||
.charts .chart .media_result .data .info .rating:before { |
|||
content: "\e031"; |
|||
font-family: 'Elusive-Icons'; |
|||
font-size: 14px; |
|||
margin: 0 5px 0 0; |
|||
vertical-align: bottom; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .genres { |
|||
font-size: 11px; |
|||
font-style: italic; |
|||
text-align: right; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .plot { |
|||
display: block; |
|||
font-size: 11px; |
|||
overflow: hidden; |
|||
text-align: justify; |
|||
height: 100%; |
|||
z-index: 2; |
|||
top: 64px; |
|||
position: absolute; |
|||
background: #4e5969; |
|||
cursor: pointer; |
|||
transition: all .4s ease-in-out; |
|||
padding: 0 3px 10px 0; |
|||
} |
|||
.charts .chart .media_result .data:before { |
|||
bottom: 0; |
|||
content: ''; |
|||
display: block; |
|||
height: 10px; |
|||
right: 0; |
|||
left: 0; |
|||
bottom: 10px; |
|||
position: absolute; |
|||
background: linear-gradient( |
|||
0deg, |
|||
rgba(78, 89, 105, 1) 0%, |
|||
rgba(78, 89, 105, 0) 100% |
|||
); |
|||
z-index: 3; |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.charts .chart .media_result .data .info .plot.full { |
|||
top: 0; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.charts .chart .media_result .data { |
|||
cursor: default; |
|||
} |
|||
|
|||
.charts .chart .media_result .options { |
|||
left: 150px; |
|||
} |
|||
.charts .chart .media_result .options select[name=title] { width: 100%; } |
|||
.charts .chart .media_result .options select[name=profile] { width: 100%; } |
|||
.charts .chart .media_result .options select[name=category] { width: 100%; } |
|||
|
|||
.charts .chart .media_result .button { |
|||
position: absolute; |
|||
margin: 2px 0 0 0; |
|||
right: 15px; |
|||
bottom: 15px; |
|||
} |
|||
|
|||
|
|||
.charts .chart .media_result .thumbnail { |
|||
width: 100px; |
|||
position: absolute; |
|||
left: 50px; |
|||
} |
|||
|
|||
.charts .chart .media_result div.chart_number { |
|||
color: white; |
|||
position: absolute; |
|||
top: 0; |
|||
padding: 10px; |
|||
font: bold 2em/1em Helvetica, Sans-Serif; |
|||
width: 50px; |
|||
height: 100%; |
|||
} |
|||
|
|||
.charts .chart .media_result div.chart_number.chart_in_wanted { |
|||
background: rgb(0, 255, 40); /* fallback color */ |
|||
background: rgba(0, 255, 40, 0.3); |
|||
} |
|||
.charts .chart .media_result div.chart_number.chart_in_library { |
|||
background: rgb(0, 202, 32); /* fallback color */ |
|||
background: rgba(0, 202, 32, 0.3); |
|||
} |
|||
|
|||
|
|||
.charts .chart .media_result .actions { |
|||
position: absolute; |
|||
top: 10px; |
|||
right: 10px; |
|||
display: none; |
|||
width: 90px; |
|||
} |
|||
.charts .chart .media_result:hover .actions { |
|||
display: block; |
|||
} |
|||
.charts .chart .media_result:hover h2 .title { |
|||
opacity: 0; |
|||
} |
|||
.charts .chart .media_result .data.open .actions { |
|||
display: none; |
|||
} |
|||
|
|||
.charts .chart .media_result .actions a { |
|||
margin-left: 10px; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
|
|||
.toggle_menu { |
|||
height: 50px; |
|||
} |
|||
|
|||
.toggle_menu a { |
|||
display: block; |
|||
width: 50%; |
|||
float: left; |
|||
color: rgba(255,255,255,.6); |
|||
border-bottom: 1px solid rgba(255, 255, 255, 0.0666667); |
|||
} |
|||
|
|||
.toggle_menu a:hover { |
|||
border-color: #047792; |
|||
border-width: 4px; |
|||
color: #fff; |
|||
} |
|||
|
|||
.toggle_menu a.active { |
|||
border-bottom: 4px solid #04bce6; |
|||
color: #fff; |
|||
} |
|||
|
|||
.toggle_menu a:last-child { |
|||
float: right; |
|||
} |
|||
|
|||
.toggle_menu h2 { |
|||
height: 40px; |
|||
} |
|||
|
@ -0,0 +1,166 @@ |
|||
var Charts = new Class({ |
|||
|
|||
Implements: [Options, Events], |
|||
|
|||
initialize: function(options){ |
|||
var self = this; |
|||
self.setOptions(options); |
|||
|
|||
self.create(); |
|||
}, |
|||
|
|||
create: function(){ |
|||
var self = this; |
|||
|
|||
self.el_refreshing_text = new Element('span.refreshing', { |
|||
'text': 'Refreshing charts...' |
|||
}); |
|||
|
|||
self.el_refresh_link = new Element('a.refresh', { |
|||
'href': '#', |
|||
'text': 'Refresh charts', |
|||
'events': { |
|||
'click': function(e) { |
|||
e.preventDefault(); |
|||
self.el.getChildren('div.chart').destroy(); |
|||
self.el_refreshing_text.show(); |
|||
self.el_refresh_link.hide(); |
|||
self.api_request = Api.request('charts.view', { |
|||
'data': { 'force_update': 1 }, |
|||
'onComplete': self.fill.bind(self) |
|||
}); |
|||
} |
|||
} |
|||
}).hide(); |
|||
|
|||
self.el_refresh_container = new Element('div.refresh').grab( |
|||
self.el_refreshing_text |
|||
).grab(self.el_refresh_link); |
|||
|
|||
self.el_no_charts_enabled = new Element('p.no_charts_enabled', { |
|||
'html': 'Hey, it looks like you have no charts enabled at the moment. If you\'d like some great movie suggestions you can go to <a href="' + App.createUrl('settings/display') + '">settings</a> and turn on some charts of your choice.' |
|||
}).hide(); |
|||
|
|||
self.el = new Element('div.charts').grab( |
|||
self.el_no_charts_enabled |
|||
).grab(self.el_refresh_container); |
|||
|
|||
if( Cookie.read('suggestions_charts_menu_selected') === 'charts') |
|||
self.el.show(); |
|||
else |
|||
self.el.hide(); |
|||
|
|||
self.api_request = Api.request('charts.view', { |
|||
'onComplete': self.fill.bind(self) |
|||
}); |
|||
|
|||
}, |
|||
|
|||
fill: function(json){ |
|||
|
|||
var self = this; |
|||
|
|||
self.el_refreshing_text.hide(); |
|||
self.el_refresh_link.show(); |
|||
|
|||
if(!json || json.count == 0){ |
|||
self.el_no_charts_enabled.show(); |
|||
self.el_refresh_link.show(); |
|||
self.el_refreshing_text.hide(); |
|||
} |
|||
else { |
|||
self.el_no_charts_enabled.hide(); |
|||
|
|||
json.charts.sort(function(a, b) { |
|||
return a.order - b.order; |
|||
}); |
|||
|
|||
Object.each(json.charts, function(chart){ |
|||
|
|||
var c = new Element('div.chart').grab( |
|||
new Element('h3').grab( new Element('a', { |
|||
'text': chart.name, |
|||
'href': chart.url |
|||
})) |
|||
); |
|||
|
|||
var it = 1; |
|||
|
|||
Object.each(chart.list, function(movie){ |
|||
|
|||
var m = new Block.Search.MovieItem(movie, { |
|||
'onAdded': function(){ |
|||
self.afterAdded(m, movie) |
|||
} |
|||
}); |
|||
var in_database_class = movie.in_wanted ? '.chart_in_wanted' : (movie.in_library ? '.chart_in_library' : ''); |
|||
var in_database_title = movie.in_wanted ? 'Movie in wanted list' : (movie.in_library ? 'Movie in library' : ''); |
|||
m.el.grab( new Element('div.chart_number' + in_database_class, { 'text': it++, 'title': in_database_title })); |
|||
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 |
|||
})) |
|||
) |
|||
); |
|||
m.data_container.removeEvents('click'); |
|||
|
|||
var plot = false; |
|||
if(m.info.plot && m.info.plot.length > 0) |
|||
plot = m.info.plot; |
|||
|
|||
// Add rating
|
|||
m.info_container.adopt( |
|||
m.rating = m.info.rating && m.info.rating.imdb && m.info.rating.imdb.length == 2 && parseFloat(m.info.rating.imdb[0]) > 0 ? new Element('span.rating', { |
|||
'text': parseFloat(m.info.rating.imdb[0]), |
|||
'title': parseInt(m.info.rating.imdb[1]) + ' votes' |
|||
}) : null, |
|||
m.genre = m.info.genres && m.info.genres.length > 0 ? new Element('span.genres', { |
|||
'text': m.info.genres.slice(0, 3).join(', ') |
|||
}) : null, |
|||
m.plot = plot ? new Element('span.plot', { |
|||
'text': plot, |
|||
'events': { |
|||
'click': function(){ |
|||
this.toggleClass('full') |
|||
} |
|||
} |
|||
}) : null |
|||
) |
|||
|
|||
$(m).inject(c); |
|||
|
|||
}); |
|||
|
|||
$(c).inject(self.el_refresh_container, 'before'); |
|||
|
|||
}); |
|||
|
|||
} |
|||
|
|||
self.fireEvent('loaded'); |
|||
|
|||
}, |
|||
|
|||
afterAdded: function(m, movie){ |
|||
var self = this; |
|||
|
|||
$(m).getElement('div.chart_number') |
|||
.addClass('chart_in_wanted') |
|||
.set('title', 'Movie in wanted list'); |
|||
|
|||
}, |
|||
|
|||
toElement: function(){ |
|||
return this.el; |
|||
} |
|||
|
|||
}) |
Loading…
Reference in new issue