diff --git a/gui/slick/interfaces/default/home_recommendedShows.tmpl b/gui/slick/interfaces/default/home_recommendedShows.tmpl
new file mode 100644
index 00000000..d6ccea86
--- /dev/null
+++ b/gui/slick/interfaces/default/home_recommendedShows.tmpl
@@ -0,0 +1,64 @@
+#import os.path
+#import json
+#import sickbeard
+#set global $header="Recommended Shows"
+#set global $title="Recommended Shows"
+
+#set global $sbPath="../.."
+
+#set global $statpath="../.."#
+#set global $topmenu="home"#
+#import os.path
+
+#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl")
+
+
+
+
+
+
+
+#if $varExists('header')
+
+#else
+
$title
+#end if
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#include $os.path.join($sickbeard.PROG_DIR,"gui/slick/interfaces/default/inc_bottom.tmpl")
diff --git a/gui/slick/js/addExistingShow.js b/gui/slick/js/addExistingShow.js
index 18498488..f4d04767 100644
--- a/gui/slick/js/addExistingShow.js
+++ b/gui/slick/js/addExistingShow.js
@@ -37,7 +37,7 @@ $(document).ready(function() {
$('.dir_check').each(function(i,w){
if ($(w).is(':checked')) {
if (url.length)
- url += '&'
+ url += '&';
url += 'rootDir=' + encodeURIComponent($(w).attr('id'));
}
});
diff --git a/gui/slick/js/recommendedShows.js b/gui/slick/js/recommendedShows.js
new file mode 100644
index 00000000..d97fa773
--- /dev/null
+++ b/gui/slick/js/recommendedShows.js
@@ -0,0 +1,144 @@
+$(document).ready(function () {
+ function getRecommendedShows() {
+ $.getJSON(sbRoot + '/home/addShows/getRecommendedShows', {}, function (data) {
+ var firstResult = true;
+ var resultStr = '
';
+ $('#searchResults').html(resultStr);
+ updateSampleText();
+ myform.loadsection(0);
+ });
+ }
+
+ $('#addShowButton').click(function () {
+ // if they haven't picked a show don't let them submit
+ if (!$("input:radio[name='whichSeries']:checked").val() && !$("input:hidden[name='whichSeries']").val().length) {
+ alert('You must choose a show to continue');
+ return false;
+ }
+
+ $('#recommendedShowsForm').submit();
+ });
+
+ $('#qualityPreset').change(function () {
+ myform.loadsection(2);
+ });
+
+ var myform = new formtowizard({
+ formid: 'recommendedShowsForm',
+ revealfx: ['slide', 500],
+ oninit: function () {
+ getRecommendedShows();
+ updateSampleText();
+ }
+ });
+
+ function goToStep(num) {
+ $('.step').each(function () {
+ if ($.data(this, 'section') + 1 == num) {
+ $(this).click();
+ }
+ });
+ }
+
+ function updateSampleText() {
+ // if something's selected then we have some behavior to figure out
+
+ var show_name, sep_char;
+ // if they've picked a radio button then use that
+ if ($('input:radio[name=whichSeries]:checked').length) {
+ show_name = $('input:radio[name=whichSeries]:checked').val().split('|')[2];
+ } else {
+ show_name = '';
+ }
+
+ var sample_text = 'Adding show
' + show_name + ' into
';
+
+ // if we have a root dir selected, figure out the path
+ if ($("#rootDirs option:selected").length) {
+ var root_dir_text = $('#rootDirs option:selected').val();
+ if (root_dir_text.indexOf('/') >= 0) {
+ sep_char = '/';
+ } else if (root_dir_text.indexOf('\\') >= 0) {
+ sep_char = '\\';
+ } else {
+ sep_char = '';
+ }
+
+ if (root_dir_text.substr(sample_text.length - 1) != sep_char) {
+ root_dir_text += sep_char;
+ }
+ root_dir_text += '||' + sep_char;
+
+ sample_text += root_dir_text;
+ } else if ($('#fullShowPath').length && $('#fullShowPath').val().length) {
+ sample_text += $('#fullShowPath').val();
+ } else {
+ sample_text += 'unknown dir.';
+ }
+
+ sample_text += '';
+
+ // if we have a show name then sanitize and use it for the dir name
+ if (show_name.length) {
+ $.get(sbRoot + '/home/addShows/sanitizeFileName', {name: show_name}, function (data) {
+ $('#displayText').html(sample_text.replace('||', data));
+ });
+ // if not then it's unknown
+ } else {
+ $('#displayText').html(sample_text.replace('||', '??'));
+ }
+
+ // also toggle the add show button
+ if (($("#rootDirs option:selected").length || ($('#fullShowPath').length && $('#fullShowPath').val().length)) &&
+ ($('input:radio[name=whichSeries]:checked').length)) {
+ $('#addShowButton').attr('disabled', false);
+ } else {
+ $('#addShowButton').attr('disabled', true);
+ }
+ }
+
+ $('#rootDirText').change(updateSampleText);
+ $('#whichSeries').live('change', updateSampleText);
+
+});
diff --git a/sickbeard/notifiers/trakt.py b/sickbeard/notifiers/trakt.py
index d16f63c3..a4fb3f07 100644
--- a/sickbeard/notifiers/trakt.py
+++ b/sickbeard/notifiers/trakt.py
@@ -46,7 +46,7 @@ class TraktNotifier:
# URL parameters
data = {
- 'indexer_id': ep_obj.show.indexerid,
+ 'tvdb_id': ep_obj.show.indexerid,
'title': ep_obj.show.name,
'year': ep_obj.show.startyear,
'episodes': [{
@@ -60,6 +60,26 @@ class TraktNotifier:
if sickbeard.TRAKT_REMOVE_WATCHLIST:
TraktCall("show/episode/unwatchlist/%API%", self._api(), self._username(), self._password(), data)
+
+ def update_show_library(self, show_obj):
+ """
+ Sends a request to trakt indicating that the given show and all its episodes is part of our library.
+
+ show_obj: The TVShow object to add to trakt
+ """
+
+ if sickbeard.USE_TRAKT:
+
+ # URL parameters
+ data = {
+ 'tvdb_id': show_obj.indexerid,
+ 'title': show_obj.name,
+ 'year': show_obj.startyear,
+ }
+
+ if data is not None:
+ TraktCall("show/library/%API%", self._api(), self._username(), self._password(), data)
+
def test_notify(self, api, username, password):
"""
Sends a test notification to trakt with the given authentication info and returns a boolean
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index c6328e9a..2da67aa7 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -65,6 +65,7 @@ from lib.unrar2 import RarFile
from lib import subliminal
import tornado
+from trakt import TraktCall
try:
import json
@@ -1046,9 +1047,11 @@ class Manage(MainHandler):
exceptions_list = []
- curErrors += Home(self.application, self.request).editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list,
- new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime,
- scene=new_scene, directCall=True)
+ curErrors += Home(self.application, self.request).editShow(curShow, new_show_dir, anyQualities,
+ bestQualities, exceptions_list,
+ new_flatten_folders, new_paused,
+ subtitles=new_subtitles, anime=new_anime,
+ scene=new_scene, directCall=True)
if curErrors:
logger.log(u"Errors: " + str(curErrors), logger.ERROR)
@@ -1612,7 +1615,8 @@ class ConfigPostProcessing(MainHandler):
wdtv_data=None, tivo_data=None, mede8er_data=None,
keep_processed_dir=None, process_method=None, process_automatically=None,
rename_episodes=None, airdate_episodes=None, unpack=None,
- move_associated_files=None, nfo_rename=None, tv_download_dir=None, naming_custom_abd=None, naming_anime=None,
+ move_associated_files=None, nfo_rename=None, tv_download_dir=None, naming_custom_abd=None,
+ naming_anime=None,
naming_abd_pattern=None, naming_strip_year=None, use_failed_downloads=None,
delete_failed=None, extra_scripts=None, skip_removed_files=None,
naming_custom_sports=None, naming_sports_pattern=None, autopostprocesser_frequency=None):
@@ -2719,6 +2723,57 @@ class NewHomeAddShows(MainHandler):
return _munge(t)
+ def recommendedShows(self, *args, **kwargs):
+ """
+ Display the new show page which collects a tvdb id, folder, and extra options and
+ posts them to addNewShow
+ """
+ t = PageTemplate(file="home_recommendedShows.tmpl")
+ t.submenu = HomeMenu()
+
+ return _munge(t)
+
+ def getRecommendedShows(self, *args, **kwargs):
+ final_results = []
+
+ if sickbeard.USE_TRAKT:
+ for myShow in sickbeard.showList:
+ notifiers.trakt_notifier.update_show_library(myShow)
+
+ logger.log(u"Getting recommended shows from Trakt.tv", logger.DEBUG)
+ recommendedlist = TraktCall("recommendations/shows.json/%API%/" + sickbeard.TRAKT_USERNAME,
+ sickbeard.TRAKT_API,
+ sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
+ if recommendedlist is None:
+ 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']))))
+
+ return json.dumps({'results': final_results})
+
+ def addRecommendedShow(self, whichSeries=None, indexerLang="en", rootDir=None, defaultStatus=None,
+ anyQualities=None, bestQualities=None, flatten_folders=None, subtitles=None,
+ fullShowPath=None, other_shows=None, skipShow=None, providedIndexer=None, anime=None,
+ scene=None):
+
+ indexer = 1
+ indexer_name = sickbeard.indexerApi(int(indexer)).name
+ show_url = whichSeries.split('|')[1]
+ indexer_id = whichSeries.split('|')[0]
+ show_name = whichSeries.split('|')[2]
+ first_aired = whichSeries.split('|')[4]
+
+ self.addNewShow('|'.join([indexer_name, str(indexer), show_url, indexer_id, show_name, first_aired]),
+ indexerLang, rootDir,
+ defaultStatus,
+ anyQualities, bestQualities, flatten_folders, subtitles, fullShowPath, other_shows,
+ skipShow, providedIndexer, anime, scene)
+
+ return self.redirect('/home/')
def existingShows(self, *args, **kwargs):
"""
@@ -3004,7 +3059,8 @@ class Home(MainHandler):
self.set_header('Access-Control-Allow-Headers', 'x-requested-with')
if sickbeard.started:
- return callback + '(' + json.dumps({"msg": str(sickbeard.PID), "restarted": str(sickbeard.restarted)}) + ');'
+ return callback + '(' + json.dumps(
+ {"msg": str(sickbeard.PID), "restarted": str(sickbeard.restarted)}) + ');'
else:
return callback + '(' + json.dumps({"msg": "nope", "restarted": str(sickbeard.restarted)}) + ');'