diff --git a/CHANGES.md b/CHANGES.md index 70137352..e04cbb26 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -63,6 +63,8 @@ * Change replace trakt with libtrakt for API v2 * Change Trakt notification config to only handle PIN authentication with the service * Remove all other Trakt deprecated API V1 service features pending reconsideration +* Change increase show search capability when using plain text and also add TVDB id, IMDb id and IMDb url search +* Change improve existing show page and the handling when an attempt to add a show to an existing location [develop changelog] Enable Alpha Ratio again now that the secure login page over https is fixed diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css index a4a38cd0..84c469bb 100644 --- a/gui/slick/css/dark.css +++ b/gui/slick/css/dark.css @@ -526,7 +526,7 @@ h2.day, h2.network{ .carousel-indicators .active{ background:#8DBEEE; border-color:#8DBEEE -} +} /* ======================================================================= config*.tmpl @@ -655,6 +655,7 @@ span.path{ background-color:#333 } +#addRootDirTable td label .filepath.red-text, .red-text{ color:#d33 } @@ -1444,4 +1445,4 @@ jquery.confirm.css #confirmBox .red:hover{ background-color:#A13331 -} \ No newline at end of file +} diff --git a/gui/slick/css/light.css b/gui/slick/css/light.css index f44be5e6..f3906ddb 100644 --- a/gui/slick/css/light.css +++ b/gui/slick/css/light.css @@ -23,12 +23,12 @@ inc_top.tmpl background:url("../css/lib/images/animated-overlay.gif") } -.ui-dialog, +.ui-dialog, .ui-dialog-buttonpane{ background:#eceadf url("../css/lib/images/ui-bg_fine-grain_10_eceadf_60x60.png") 50% 50% repeat !important } -.ui-accordion-content, +.ui-accordion-content, .ui-tabs-panel{ background:#ededed !important; background-image:none !important @@ -50,41 +50,41 @@ inc_top.tmpl background:#fff url("../css/lib/images/ui-bg_flat_0_ffffff_40x100.png") 50% 50% repeat-x } -.ui-state-default, -.ui-widget-content .ui-state-default, +.ui-state-default, +.ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default{ background:#fff; border:1px solid #CCC } -.ui-state-hover, -.ui-widget-content .ui-state-hover, -.ui-widget-header .ui-state-hover, -.ui-state-focus, -.ui-widget-content .ui-state-focus, +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus{ background:#fff } -.ui-state-active, -.ui-widget-content .ui-state-active, +.ui-state-active, +.ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active{ background:#F7F7F7 } -.ui-state-highlight, -.ui-widget-content .ui-state-highlight, +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight{ background:#fbf9ee url("../css/lib/images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x } -.ui-state-error, -.ui-widget-content .ui-state-error, +.ui-state-error, +.ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error{ background:#fef1ec url("../css/lib/images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x } -.ui-icon, +.ui-icon, .ui-widget-content .ui-icon{ background-image:url("../css/lib/images/ui-icons_222222_256x240.png") } @@ -97,7 +97,7 @@ inc_top.tmpl background-image:url("../css/lib/images/ui-icons_8c291d_256x240.png") } -.ui-state-hover .ui-icon, +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon{ background-image:url("../css/lib/images/ui-icons_222222_256x240.png") } @@ -110,7 +110,7 @@ inc_top.tmpl background-image:url("../css/lib/images/ui-icons_2e83ff_256x240.png") } -.ui-state-error .ui-icon, +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon{ background-image:url("../css/lib/images/ui-icons_cd0a0a_256x240.png") } @@ -345,7 +345,7 @@ home_postprocess.tmpl /* ======================================================================= -displayShow.tmpl +displayShow.tmpl ========================================================================== */ tr.seasonheader{ @@ -508,7 +508,7 @@ h2.day, h2.network{ .carousel-indicators .active{ background:#C7DB40; border-color:#C7DB40 -} +} /* ======================================================================= config*.tmpl @@ -630,6 +630,7 @@ span.path{ background-color:#f5f1e4 } +#addRootDirTable td label .filepath.red-text, .red-text{ color:#d33 } diff --git a/gui/slick/interfaces/default/home_addExistingShow.tmpl b/gui/slick/interfaces/default/home_addExistingShow.tmpl index 9b0a213f..d3784e83 100644 --- a/gui/slick/interfaces/default/home_addExistingShow.tmpl +++ b/gui/slick/interfaces/default/home_addExistingShow.tmpl @@ -10,14 +10,11 @@ #import os.path #include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl') - - - - - + + + + #if $varExists('header')

$header

@@ -36,48 +37,56 @@
-

Tip: shows are added quicker when usable show nfo and xml metadata is found

+ +

Tip: shows are added quicker when usable show nfo and xml metadata is found

-

- - -

+

+ + +

-
- -
-
+
+ +
+
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_rootDirs.tmpl') +
-
-
-
+
+
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_addShowOptions.tmpl') +
-
-
-
+
+
+ -

The following parent folder(s) are scanned for existing shows. Toggle a folder to display shows

+

The following parent folder$multi_parents scanned for + #if not $kwargs.get('hash_dir', None)#existing shows. Toggle a folder to display shows#else#the existing show...#end if# +

+#if not $kwargs.get('hash_dir', None)

shows not known to SickGear are listed below...

+#end if

+#if not $kwargs.get('hash_dir', None)

If you tried to add a show, arrived here and can't see the folder, then that show may already be in your show list.

+#end if - + -#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl') \ No newline at end of file +#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl') diff --git a/gui/slick/interfaces/default/home_massAddTable.tmpl b/gui/slick/interfaces/default/home_massAddTable.tmpl index 1f0faf79..96aa8246 100644 --- a/gui/slick/interfaces/default/home_massAddTable.tmpl +++ b/gui/slick/interfaces/default/home_massAddTable.tmpl @@ -2,48 +2,67 @@ #from sickbeard.helpers import anon_url - - - - - - - -#for $curDir in $dirList: -#if $curDir['added_already']: -#continue -#end if - -#set $show_id = $curDir['dir'] -#if $curDir['existing_info'][0]: -#set $show_id = $show_id + '|' + $str($curDir['existing_info'][0]) + '|' + $str($curDir['existing_info'][1]) -#set $indexer = $curDir['existing_info'][2] -#end if - -#set $indexer = 0 -#if $curDir['existing_info'][0]: - #set $indexer = $curDir['existing_info'][2] -#elif $sickbeard.INDEXER_DEFAULT > 0: - #set $indexer = $sickbeard.INDEXER_DEFAULT -#end if - - - - - #if $curDir['existing_info'][1] and $indexer > 0: - - #else: - + + + + + + + + + + + + + + +#for $curDir in $dirList + #if $curDir['added_already'] and None is $curDir.get('highlight') + #continue #end if - - + + #set $show_id = $curDir['dir'] + #if $curDir['existing_info'][0] + #set $show_id = $show_id + '|' + $str($curDir['existing_info'][0]) + '|' + $str($curDir['existing_info'][1]) + #set $indexer = $curDir['existing_info'][2] + #end if + + #set $indexer = 0 + #if $curDir['existing_info'][0] + #set $indexer = $curDir['existing_info'][2] + #elif 0 < $sickbeard.INDEXER_DEFAULT + #set $indexer = $sickbeard.INDEXER_DEFAULT + #end if + + + + + #if $curDir['existing_info'][1] and $indexer > 0 + + #else + + #end if + + #end for - - -
Parent\show folderShow name
(tvshow.nfo)
TV database
Manage Directories
$curDir['existing_info'][1]?
+ + Parent\show folderShow name
(tvshow.nfo)
TV info source
+ Manage Directories +
- -
+ + + + + $curDir['existing_info'][1] + ? + +
\ No newline at end of file + + diff --git a/gui/slick/interfaces/default/home_newShow.tmpl b/gui/slick/interfaces/default/home_newShow.tmpl index 3a3da7d0..b92008c4 100644 --- a/gui/slick/interfaces/default/home_newShow.tmpl +++ b/gui/slick/interfaces/default/home_newShow.tmpl @@ -65,7 +65,7 @@
-

* SickGear supports english episodes. The language choice is used for fetching show data and episode filenames

+

Enter show name, TVDB ID, IMDb Url, or IMDb ID.  *SickGear supports english, language is used for show/episode data

#end if @@ -116,4 +116,4 @@
-#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl') \ No newline at end of file +#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 1b08f888..98d2dfe2 100644 --- a/gui/slick/js/addExistingShow.js +++ b/gui/slick/js/addExistingShow.js @@ -28,6 +28,7 @@ $(document).ready(function(){ window.location.href = sbRoot + '/home/addShows/addExistingShows' + '?promptForSettings=' + ($('#promptForSettings').prop('checked') ? 'on' : 'off') + + (undefined !== $.sgSid && 0 < $.sgSid.length ? '&sid=' + $.sgSid : '') + '&shows_to_add=' + dirArr.join('&shows_to_add='); }); @@ -47,7 +48,7 @@ $(document).ready(function(){ + ' height="32" width="32" />' + ' scanning parent folders...'); - $.get(sbRoot + '/home/addShows/massAddTable', + $.get(sbRoot + '/home/addShows/massAddTable' + (undefined !== $.sgHashDir && 0 < $.sgHashDir.length ? '?hash_dir=' + $.sgHashDir : ''), url, function(data){ $('#tableDiv').html(data); @@ -90,4 +91,4 @@ $(document).ready(function(){ $('html,body').animate({scrollTop: 0}, 1000); }); -}); \ No newline at end of file +}); diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index a714e55f..60a694f9 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -40,6 +40,7 @@ from sickbeard.common import SNATCHED, UNAIRED, IGNORED, ARCHIVED, WANTED, FAILE from sickbeard.common import SD, HD720p, HD1080p from sickbeard.exceptions import ex from sickbeard.helpers import remove_article, starify +from sickbeard.indexers.indexer_config import INDEXER_TVDB, INDEXER_TVRAGE from sickbeard.scene_exceptions import get_scene_exceptions from sickbeard.scene_numbering import get_scene_numbering, set_scene_numbering, get_scene_numbering_for_show, \ get_xem_numbering_for_show, get_scene_absolute_numbering_for_show, get_xem_absolute_numbering_for_show, \ @@ -2052,6 +2053,16 @@ class NewHomeAddShows(Home): results = {} final_results = [] + search_id, indexer_id = '', None + search_id = '' + try: + search_id = re.search(r'(?m)((?:tt\d{4,})|^\d{4,}$)', search_term).group(1) + resp = self.getTrakt('/search?id_type=%s&id=%s' % (('tvdb', 'imdb')['tt' in search_id], search_id))[0] + search_term = resp['show']['title'] + indexer_id = resp['show']['ids']['tvdb'] + except: + search_term = (search_term, '')['tt' in search_id] + # Query Indexers for each search term and build the list of results for indexer in sickbeard.indexerApi().indexers if not int(indexer) else [int(indexer)]: lINDEXER_API_PARMS = sickbeard.indexerApi(indexer).api_params.copy() @@ -2059,24 +2070,64 @@ class NewHomeAddShows(Home): lINDEXER_API_PARMS['custom_ui'] = classes.AllShowsListUI t = sickbeard.indexerApi(indexer).indexer(**lINDEXER_API_PARMS) - logger.log('Searching for Show with searchterm: %s on Indexer: %s' % ( - search_term, sickbeard.indexerApi(indexer).name), logger.DEBUG) try: # add search results - results.setdefault(indexer, []).extend(t[search_term]) + if bool(indexer_id): + logger.log('Fetching show using id: %s (%s) from tv datasource %s' % ( + search_id, search_term, sickbeard.indexerApi(indexer).name), logger.DEBUG) + results.setdefault('tt' in search_id and 3 or indexer, []).extend( + [{'id': indexer_id, 'seriesname': t[indexer_id]['seriesname'], 'firstaired': t[indexer_id]['firstaired']}]) + break + else: + logger.log('Searching for shows using search term: %s from tv datasource %s' % ( + search_term, sickbeard.indexerApi(indexer).name), logger.DEBUG) + results.setdefault(indexer, []).extend(t[search_term]) except Exception as e: - continue + pass + # Query trakt for tvdb ids + try: + logger.log('Searching for show using search term: %s from tv datasource Trakt' % search_term, logger.DEBUG) + resp = self.getTrakt('/search?query=%s&type=show' % search_term) + tvdb_ids = [] + for tvdb_item in results[INDEXER_TVDB]: + tvdb_ids.append(int(tvdb_item['id'])) + results_trakt = [] + for item in resp: + if 'tvdb' in item['show']['ids'] and item['show']['ids']['tvdb'] and \ + item['show']['ids']['tvdb'] not in tvdb_ids: + results_trakt.append({'id': item['show']['ids']['tvdb'], 'seriesname': item['show']['title'], + 'firstaired': item['show']['year']}) + results.update({3: results_trakt}) + except: + pass + + id_names = [None, sickbeard.indexerApi(INDEXER_TVDB).name, sickbeard.indexerApi(INDEXER_TVRAGE).name, + '%s via Trakt' % sickbeard.indexerApi(INDEXER_TVDB).name] map(final_results.extend, - ([[sickbeard.indexerApi(id).name, id, sickbeard.indexerApi(id).config['show_url'], int(show['id']), + ([['%s%s' % (id_names[id], helpers.findCertainShow(sickbeard.showList, int(show['id'])) and ' - exists in db' or ''), + (id, INDEXER_TVDB)[id == 3], sickbeard.indexerApi((id, INDEXER_TVDB)[id == 3]).config['show_url'], int(show['id']), show['seriesname'], show['firstaired']] for show in shows] for id, shows in results.items())) lang_id = sickbeard.indexerApi().config['langabbv_to_id'][lang] return json.dumps({'results': final_results, 'langid': lang_id}) - def massAddTable(self, rootDir=None): + def getTrakt(self, url, *args, **kwargs): + + filtered = [] + try: + resp = TraktAPI(ssl_verify=sickbeard.TRAKT_VERIFY, timeout=sickbeard.TRAKT_TIMEOUT).trakt_request(url) + if len(resp): + filtered = resp + except traktException as e: + logger.log(u'Could not connect to Trakt service: %s' % ex(e), logger.WARNING) + + return filtered + + def massAddTable(self, rootDir=None, **kwargs): t = PageTemplate(headers=self.request.headers, file='home_massAddTable.tmpl') t.submenu = self.HomeMenu() + t.kwargs = kwargs if not rootDir: return 'No folders selected.' @@ -2100,12 +2151,34 @@ class NewHomeAddShows(Home): dir_list = [] + display_one_dir = file_list = None + if kwargs.get('hash_dir'): + try: + for root_dir in sickbeard.ROOT_DIRS.split('|')[1:]: + try: + file_list = ek.ek(os.listdir, root_dir) + except: + continue + + for cur_file in file_list: + + cur_path = ek.ek(os.path.normpath, ek.ek(os.path.join, root_dir, cur_file)) + if not ek.ek(os.path.isdir, cur_path): + continue + + display_one_dir = kwargs.get('hash_dir') == str(abs(hash(cur_path))) + if display_one_dir: + raise ValueError('hash matched') + except ValueError: + pass + myDB = db.DBConnection() for root_dir in root_dirs: - try: - file_list = ek.ek(os.listdir, root_dir) - except: - continue + if not file_list: + try: + file_list = ek.ek(os.listdir, root_dir) + except: + continue for cur_file in file_list: @@ -2113,11 +2186,14 @@ class NewHomeAddShows(Home): if not ek.ek(os.path.isdir, cur_path): continue + highlight = kwargs.get('hash_dir') == str(abs(hash(cur_path))) + if display_one_dir and not highlight: + continue cur_dir = { 'dir': cur_path, - 'display_dir': '' + ek.ek(os.path.dirname, cur_path) + os.sep + '' + ek.ek( - os.path.basename, - cur_path), + 'highlight': highlight, + 'name': ek.ek(os.path.basename, cur_path), + 'path': '%s%s' % (ek.ek(os.path.dirname, cur_path), os.sep) } # see if the folder is in XBMC already @@ -2311,6 +2387,8 @@ class NewHomeAddShows(Home): t = PageTemplate(headers=self.request.headers, file='home_addExistingShow.tmpl') t.submenu = self.HomeMenu() t.enable_anime_options = False + t.kwargs = kwargs + t.multi_parents = helpers.maybe_plural(len(sickbeard.ROOT_DIRS.split('|')[1:])) and 's are' or ' is' return t.respond() @@ -2385,7 +2463,7 @@ class NewHomeAddShows(Home): # blanket policy - if the dir exists you should have used 'add existing show' numbnuts if ek.ek(os.path.isdir, show_dir) and not fullShowPath: ui.notifications.error('Unable to add show', u'Found existing folder: ' + show_dir) - return self.redirect('/home/addShows/existingShows/') + return self.redirect('/home/addShows/existingShows?sid=%s&hash_dir=%s' % (indexer_id, abs(hash(show_dir)))) # don't create show dir if config says not to if sickbeard.ADD_SHOWS_WO_DIR: @@ -2448,12 +2526,16 @@ class NewHomeAddShows(Home): return (indexer, show_dir, indexer_id, show_name) - def addExistingShows(self, shows_to_add=None, promptForSettings=None): + def addExistingShows(self, shows_to_add=None, promptForSettings=None, **kwargs): """ Receives a dir list and add them. Adds the ones with given TVDB IDs first, then forwards along to the newShow page. """ + if kwargs.get('sid', None): + return self.redirect('/home/addShows/newShow?show_to_add=%s&use_show_name=True' % + '|'.join(['', '', '', kwargs.get('sid', '')])) + # grab a list of other shows to add, if provided if not shows_to_add: shows_to_add = [] @@ -2470,7 +2552,7 @@ class NewHomeAddShows(Home): split_vals = cur_dir.split('|') if len(split_vals) < 3: dirs_only.append(cur_dir) - if not '|' in cur_dir: + if '|' not in cur_dir: dirs_only.append(cur_dir) else: indexer, show_dir, indexer_id, show_name = self.split_extra_show(cur_dir) @@ -2480,7 +2562,6 @@ class NewHomeAddShows(Home): indexer_id_given.append((int(indexer), show_dir, int(indexer_id), show_name)) - # if they want me to prompt for settings then I will just carry on to the newShow page if promptForSettings and shows_to_add: return self.newShow(shows_to_add[0], shows_to_add[1:])