Added trending shows feature, this allows you to choose from a wide selection of popular/trending shows with rating stats and easily add the show into SR by simply clicking the plus sign.

This commit is contained in:
echel0n 2014-07-01 01:49:12 -07:00
parent 9136df2ae5
commit 130daf7d0a
7 changed files with 232 additions and 32 deletions

92
gui/slick/css/trakt.css Normal file
View file

@ -0,0 +1,92 @@
.traktShowDiv {
clear: both;
border-left: 1px solid #CCCCCC;
border-right: 1px solid #CCCCCC;
border-bottom: 1px solid #CCCCCC;
margin: auto;
padding: 0px;
text-align: left;
width: 750px;
}
.traktShowDiv a, .traktShowDiv a:link, .traktShowDiv a:visited, .traktShowDiv a:hover {
text-decoration: none;
background: none;
}
.traktShowTitle a {
color: #000000;
float: left;
padding-top: 3px;
line-height: 1.2em;
font-size: 1.1em;
text-shadow: -1px -1px 0 #FFF);
}
.traktShowTitleIcons {
float: right;
padding: 3px 5px;
}
.traktShowDiv .title {
font-weight: 900;
color: #333;
}
.imgWrapper {
background: url("../images/loading.gif") no-repeat scroll center center #FFFFFF;
border: 3px solid #FFFFFF;
box-shadow: 1px 1px 2px 0 #555555;
float: left;
height: 50px;
overflow: hidden;
text-indent: -3000px;
width: 50px;
}
.imgWrapper .traktPosterThumb {
float: left;
min-height: 100%;
min-width: 100%;
width: 50px;
height: auto;
position: relative;
border: none;
vertical-align: middle;
}
.traktPosterThumb {
-ms-interpolation-mode: bicubic; /* make scaling look nicer for ie */
vertical-align: top;
height: auto;
width: 160px;
border-top: 1px solid #ccc;
border-right: 1px solid #ccc;
}
.traktShowDiv th {
color: #000;
letter-spacing: 1px;
text-align: left;
background-color: #333333;
}
.traktShowDiv th.nobg {
background: #efefef;
border-top: 1px solid #666;
text-align: center;
}
.traktShowDiv td {
border-top: 1px solid #d2ebe8;
background: #fff;
padding: 5px 10px 5px 10px;
color: #000;
}
.traktShowDiv td.trakts_show {
width: 100%;
height: 90%;
border-top: 1px solid #ccc;
vertical-align: top;
background: #F5FAFA;
color: #000;
}

View file

@ -26,15 +26,23 @@
<p>For shows that you haven't downloaded yet, this option finds a show on theTVDB.com and TVRage.com, creates a directory for its episodes, and adds it to SickRage.</p>
</div>
</a>
<br/><br/>
<a href="$sbRoot/home/addShows/trendingShows/" id="btnNewShow" class="btn btn-large">
<div class="button"><img src="$sbRoot/images/add-new32.png" height="32" width="32" alt="Add Trending Shows"/></div>
<div class="buttontext">
<h2>Add Trending Show</h2>
<p>For shows that you haven't downloaded yet, this option lets you choose from a list of current trending shows with ratings to add, creates a directory for its episodes, and adds it to SickRage.</p>
</div>
</a>
<br/><br/>
#if $sickbeard.TRAKT_USE_RECOMMENDED:
<a href="$sbRoot/home/addShows/recommendedShows/" id="btnNewShow" class="btn btn-large">
<div class="button"><img src="$sbRoot/images/add-new32.png" height="32" width="32" alt="Add Recommended Shows"/></div>
<div class="buttontext">
<h2>Add Recommended Shows</h2>
<p>For shows that you haven't downloaded yet, this option recommends shows to add based on your Trakt.tv watch list, creates a directory for its episodes, and adds it to SickRage. *** Trakt.tv must be enabled ***</p>
<h2>Add Recommended Show</h2>
<p>For shows that you haven't downloaded yet, this option recommends shows to add based on your Trakt.tv show library, creates a directory for its episodes, and adds it to SickRage. *** Trakt.tv must be enabled ***</p>
</div>
</a>
<br/><br/>

View file

@ -0,0 +1,58 @@
#import sickbeard
#import datetime
#import re
#from sickbeard.common import *
#from sickbeard import sbdatetime
#set global $title="Trending Shows"
#set global $header="Trending Shows"
#set global $sbPath=".."
#set global $topmenu="comingEpisodes"
#import os.path
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl")
<script type="text/javascript" src="$sbRoot/js/plotTooltip.js?$sbPID"></script>
<link rel="stylesheet" type="text/css" href="$sbRoot/css/trakt.css?$sbPID" />
#if $varExists('header')
<h1 class="header">$header</h1>
#else
<h1 class="title">$title</h1>
#end if
<div class="traktShowDiv">
<table width="100%" cellspacing="1" border="0" cellpadding="0">
#for $i, $cur_show in $enumerate($trending_shows):
<div id="listing_${cur_show["tvdb_id"]}">
#if not $i%4
<tr>
#end if
<th style="background-color: #efefef;" valign="top">
<td class="trakt_show">
<a href="${cur_show["url"]}"><img alt="" class="traktPosterThumb" src="${cur_show["images"]["poster"]}" /></a>
<div class="clearfix">
<h2>$cur_show["ratings"]["percentage"]% <img src="$sbRoot/images/like.png"></h2>
<i>$cur_show["ratings"]["votes"] votes</i>
<div class="traktShowTitleIcons">
<a href="$sbRoot/home/addTraktShow?indexer_id=${cur_show["tvdb_id"]}&amp;showName=${cur_show["title"]}"><img alt="[add show]" height="16" width="16" src="$sbRoot/images/plus.png"></a>
</div>
</div>
</td>
</th>
</div>
#end for
</table>
</div>
<script type="text/javascript" charset="utf-8">
<!--
window.setInterval( "location.reload(true)", 600000); // Refresh every 10 minutes
//-->
</script>
#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_bottom.tmpl")

View file

@ -7,7 +7,7 @@ try:
except ImportError:
from lib import simplejson as json
def TraktCall(method, api, username, password, data = {}):
def TraktCall(method, api, username=None, password=None, data={}):
"""
A generic method for communicating with trakt. Uses the method and data provided along
with the auth info to send the command.
@ -26,19 +26,16 @@ def TraktCall(method, api, username, password, data = {}):
return None
# if the username isn't given then it failed
if not username:
return None
password = sha1(password).hexdigest()
if username and password:
password = sha1(password).hexdigest()
data["username"] = username
data["password"] = password
# replace the API string with what we found
method = method.replace("%API%", api)
data["username"] = username
data["password"] = password
# take the URL params and make a json object out of them
encoded_data = json.dumps(data);
encoded_data = json.dumps(data)
# request the URL from trakt and parse the result as json
try:

View file

@ -432,7 +432,7 @@ IGNORE_WORDS = "german,french,core2hd,dutch,swedish,reenc,MrLss"
CALENDAR_UNPROTECTED = False
TMDB_API_KEY = 'edc5f123313769de83a71e157758030b'
TRAKT_API_KEY = 'abd806c54516240c76e4ebc9c5ccf394'
__INITIALIZED__ = False
def initialize(consoleLogging=True):

View file

@ -147,9 +147,9 @@ class TraktChecker():
"""
Adds a new show with the default settings
"""
showObj = helpers.findCertainShow(sickbeard.showList, int(indexerid))
if showObj != None:
if helpers.findCertainShow(sickbeard.showList, int(indexerid)):
return
logger.log(u"Adding show " + str(indexerid))
root_dirs = sickbeard.ROOT_DIRS.split('|')
location = root_dirs[int(root_dirs[0]) + 1]
@ -161,6 +161,7 @@ class TraktChecker():
return
else:
helpers.chmodAsParent(showPath)
sickbeard.showQueueScheduler.action.addShow(1, int(indexerid), showPath, status,
int(sickbeard.QUALITY_DEFAULT),
int(sickbeard.FLATTEN_FOLDERS_DEFAULT))

View file

@ -48,7 +48,7 @@ from sickbeard import subtitles
from sickbeard import network_timezones
from sickbeard.providers import newznab, rsstorrent
from sickbeard.common import Quality, Overview, statusStrings, qualityPresetStrings, cpu_presets
from sickbeard.common import Quality, Overview, statusStrings, qualityPresetStrings, cpu_presets, SKIPPED
from sickbeard.common import SNATCHED, UNAIRED, IGNORED, ARCHIVED, WANTED, FAILED
from sickbeard.common import SD, HD720p, HD1080p
from sickbeard.exceptions import ex
@ -82,6 +82,7 @@ from lib import adba
from Cheetah.Template import Template
from tornado.web import RequestHandler, HTTPError
def authenticated(handler_class):
def wrap_execute(handler_execute):
def basicauth(handler, transforms, *args, **kwargs):
@ -125,6 +126,7 @@ def authenticated(handler_class):
handler_class._execute = wrap_execute(handler_class._execute)
return handler_class
class HTTPRedirect(Exception):
"""Exception raised when the request should be redirected."""
@ -138,9 +140,11 @@ class HTTPRedirect(Exception):
"""Use this exception as a request.handler (raise self)."""
raise self
def redirect(url, permanent=False, status=None):
raise HTTPRedirect(url, permanent, status)
@authenticated
class MainHandler(RequestHandler):
def http_error_401_handler(self):
@ -216,7 +220,7 @@ class MainHandler(RequestHandler):
def get(self, *args, **kwargs):
try:
self.finish(self._dispatch())
except HTTPRedirect,inst:
except HTTPRedirect, inst:
self.redirect(inst.url, inst.permanent, inst.status)
def post(self, *args, **kwargs):
@ -462,6 +466,7 @@ class MainHandler(RequestHandler):
browser = WebFileBrowser
class PageTemplate(Template):
def __init__(self, headers, *args, **KWs):
KWs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/",
@ -499,7 +504,7 @@ class PageTemplate(Template):
{'title': 'Manage', 'key': 'manage'},
{'title': 'Config', 'key': 'config'},
{'title': logPageTitle, 'key': 'errorlogs'},
]
]
class IndexerWebUI(MainHandler):
@ -518,6 +523,7 @@ class IndexerWebUI(MainHandler):
def _munge(string):
return unicode(string).encode('utf-8', 'xmlcharrefreplace')
def _getEpisode(show, season=None, episode=None, absolute=None):
if show is None:
return "Invalid show parameters"
@ -2643,7 +2649,7 @@ class NewHomeAddShows(MainHandler):
'display_dir': '<b>' + ek.ek(os.path.dirname, cur_path) + os.sep + '</b>' + ek.ek(
os.path.basename,
cur_path),
}
}
# see if the folder is in XBMC already
dirResults = myDB.select("SELECT * FROM tv_shows WHERE location = ?", [cur_path])
@ -2745,10 +2751,10 @@ class NewHomeAddShows(MainHandler):
logger.log(u"Could not connect to trakt service, aborting recommended list update", logger.ERROR)
return
map(final_results.append, ([int(show['tvdb_id']), show['url'], show['title'], show['overview'],
datetime.date.fromtimestamp(show['first_aired']).strftime('%Y%m%d')] for show in
recommendedlist if
not helpers.findCertainShow(sickbeard.showList, indexerid=int(show['tvdb_id']))))
map(final_results.append,
([int(show['tvdb_id']), show['url'], show['title'], show['overview'],
datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')] for show in
recommendedlist if not helpers.findCertainShow(sickbeard.showList, indexerid=int(show['tvdb_id']))))
return json.dumps({'results': final_results})
@ -2764,10 +2770,22 @@ class NewHomeAddShows(MainHandler):
show_name = whichSeries.split('|')[2]
return self.addNewShow('|'.join([indexer_name, str(indexer), show_url, indexer_id, show_name, ""]),
indexerLang, rootDir,
defaultStatus,
anyQualities, bestQualities, flatten_folders, subtitles, fullShowPath, other_shows,
skipShow, providedIndexer, anime, scene)
indexerLang, rootDir,
defaultStatus,
anyQualities, bestQualities, flatten_folders, subtitles, fullShowPath, other_shows,
skipShow, providedIndexer, anime, scene)
def trendingShows(self, *args, **kwargs):
"""
Display the new show page which collects a tvdb id, folder, and extra options and
posts them to addNewShow
"""
t = PageTemplate(headers=self.request.headers, file="home_trendingShows.tmpl")
t.submenu = HomeMenu()
t.trending_shows = TraktCall("shows/trending.json/%API%/", sickbeard.TRAKT_API_KEY)
return _munge(t)
def existingShows(self, *args, **kwargs):
"""
@ -2778,6 +2796,33 @@ class NewHomeAddShows(MainHandler):
return _munge(t)
def addTraktShow(self, indexer_id, showName):
if helpers.findCertainShow(sickbeard.showList, int(indexer_id)):
return
root_dirs = sickbeard.ROOT_DIRS.split('|')
location = root_dirs[int(root_dirs[0]) + 1]
show_dir = ek.ek(os.path.join, location, helpers.sanitizeFileName(showName))
dir_exists = helpers.makeDir(show_dir)
if not dir_exists:
logger.log(u"Unable to create the folder " + show_dir + ", can't add the show", logger.ERROR)
return
else:
helpers.chmodAsParent(show_dir)
sickbeard.showQueueScheduler.action.addShow(1, int(indexer_id), show_dir,
default_status=sickbeard.STATUS_DEFAULT,
quality=sickbeard.QUALITY_DEFAULT,
flatten_folders=sickbeard.FLATTEN_FOLDERS_DEFAULT,
subtitles=sickbeard.SUBTITLES_DEFAULT,
anime=sickbeard.ANIME_DEFAULT,
scene=sickbeard.SCENE_DEFAULT)
ui.notifications.message('Show added', 'Adding the specified show into ' + show_dir)
# done adding show
redirect('/home/')
def addNewShow(self, whichSeries=None, indexerLang="en", rootDir=None, defaultStatus=None,
anyQualities=None, bestQualities=None, flatten_folders=None, subtitles=None,
@ -3394,7 +3439,7 @@ class Home(MainHandler):
return _munge(t)
else:
return self._genericMessage("Update Failed",
"Update wasn't successful, not restarting. Check your log for more information.")
"Update wasn't successful, not restarting. Check your log for more information.")
def displayShow(self, show=None):
@ -3999,7 +4044,6 @@ class Home(MainHandler):
myDB = db.DBConnection()
myDB.mass_action(sql_l)
if int(status) == WANTED:
msg = "Backlog was automatically started for the following seasons of <b>" + showObj.name + "</b>:<br />"
for season in segment:
@ -4294,9 +4338,9 @@ class Home(MainHandler):
return json.dumps({'result': 'failure'})
class UI(MainHandler):
def add_message(self):
ui.notifications.message('Test 1', 'This is test number 1')
ui.notifications.error('Test 2', 'This is test number 2')
@ -4307,8 +4351,8 @@ class UI(MainHandler):
cur_notification_num = 1
for cur_notification in ui.notifications.get_notifications(self.request.remote_ip):
messages['notification-' + str(cur_notification_num)] = {'title': cur_notification.title,
'message': cur_notification.message,
'type': cur_notification.type}
'message': cur_notification.message,
'type': cur_notification.type}
cur_notification_num += 1
return json.dumps(messages)