Merge pull request #560 from JackDandy/feature/AddIDSearch

Change increase show search capability when using plain text and also…
This commit is contained in:
JackDandy 2015-11-16 11:55:51 +00:00
commit 35f8bc1a1e
8 changed files with 227 additions and 113 deletions

View file

@ -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

View file

@ -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
}
}

View file

@ -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
}

View file

@ -10,14 +10,11 @@
#import os.path
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl')
<script type="text/javascript" src="$sbRoot/js/qualityChooser.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/addExistingShow.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/addShowOptions.js?v=$sbPID"></script>
<script type="text/javascript" charset="utf-8">
<!--
\$(document).ready(function(){
\$.sgSid = '$kwargs.get('sid', '')';
\$.sgHashDir = '$kwargs.get('hash_dir', '')';
\$(document).ready(function(){
\$( '#tabs' ).tabs({
collapsible: true,
selected: #if $sickbeard.ROOT_DIRS then '-1' else '0'#
@ -25,6 +22,10 @@
});
//-->
</script>
<script type="text/javascript" src="$sbRoot/js/qualityChooser.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/addExistingShow.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/rootDirs.js?v=$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/addShowOptions.js?v=$sbPID"></script>
#if $varExists('header')
<h1 class="header">$header</h1>
@ -36,48 +37,56 @@
<form id="addShowForm" method="post" action="$sbRoot/home/addShows/addNewShow" accept-charset="utf-8">
<p>Tip: shows are added quicker when usable show nfo and xml metadata is found</p>
<span#if $kwargs.get('hash_dir', None)# style="display:none"#end if>
<p>Tip: shows are added quicker when usable show nfo and xml metadata is found</p>
<p style="margin-top:15px">
<input type="checkbox" id="promptForSettings" name="promptForSettings" style="vertical-align: top;" />
<label for="promptForSettings">Enable to change the following options per show, otherwise use these options with all shows added below</label>
</p>
<p style="margin-top:15px">
<input type="checkbox" id="promptForSettings" name="promptForSettings" style="vertical-align: top;" />
<label for="promptForSettings">Enable to change the following options per show, otherwise use these options with all shows added below</label>
</p>
<div id="tabs">
<ul>
<li><a href="#tabs-1">Manage parent folders</a></li>
<li><a href="#tabs-2">Custom options</a></li>
</ul>
<div id="tabs-1" class="existingtabs">
<div style="width: 430px; margin: 0px auto">
<div id="tabs">
<ul>
<li><a href="#tabs-1">Manage parent folders</a></li>
<li><a href="#tabs-2">Custom options</a></li>
</ul>
<div id="tabs-1" class="existingtabs">
<div style="width: 430px; margin: 0px auto">
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_rootDirs.tmpl')
</div>
</div>
</div>
<div id="tabs-2">
<div class="stepDiv">
<div id="tabs-2">
<div class="stepDiv">
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_addShowOptions.tmpl')
</div>
</div>
</div>
</div>
<br />
<hr />
<br />
<hr />
</span>
<p>The following parent folder(s) are scanned for existing shows. Toggle a folder to display shows</p>
<p>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#
</p>
<ul id="rootDirStaticList">
<li></li>
</ul>
#if not $kwargs.get('hash_dir', None)
<p>shows <span class="boldest">not known</span> to SickGear are listed below...</p>
#end if
<div id="tableDiv"></div>
<br />
#if not $kwargs.get('hash_dir', None)
<p>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.</p>
#end if
<input class="btn btn-primary" type="button" value="Submit" id="submitShowDirs" />
<input class="btn btn-primary" type="button" value="#if $kwargs.get('hash_dir', None)#Redo Search#else#Submit#end if#" id="submitShowDirs" />
</form>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -2,48 +2,67 @@
#from sickbeard.helpers import anon_url
<table id="addRootDirTable" class="sickbeardTable tablesorter">
<thead><tr><th class="col-checkbox"><input type="checkbox" id="checkAll" checked=checked></th><th>Parent\show folder</th><th width="20%">Show name<br />(tvshow.nfo)<th width="15%">TV database</td></tr></thead>
<tfoot>
<tr>
<th rowspan="1" colspan="4" align="left"><a href="#" class="showManage">Manage Directories</a></th>
</tr>
</tfoot>
<tbody>
#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
<tr>
<td class="col-checkbox"><input type="checkbox" id="$show_id" class="dirCheck" checked=checked></td>
<td><label for="$show_id">$curDir['display_dir']</label></td>
#if $curDir['existing_info'][1] and $indexer > 0:
<td><a href="<%= anon_url(sickbeard.indexerApi(indexer).config['show_url'], curDir['existing_info'][0]) %>" target="_new">$curDir['existing_info'][1]</a></td>
#else:
<td>?</td>
<thead>
<tr>
<th class="col-checkbox">
<input type="checkbox" id="checkAll" checked=checked>
</th>
<th>Parent\show folder</th>
<th width="20%">Show name<br />(tvshow.nfo)</th>
<th width="15%">TV info source</th>
</tr>
</thead>
<tfoot>
<tr>
<th rowspan="1" colspan="4" align="left">
<a href="#" class="showManage">Manage Directories</a>
</th>
</tr>
</tfoot>
<tbody>
#for $curDir in $dirList
#if $curDir['added_already'] and None is $curDir.get('highlight')
#continue
#end if
<td align="center">
<select name="indexer">
#for $curIndexer in $sickbeard.indexerApi().indexers.items():
<option value="$curIndexer[0]" #if $curIndexer[0] == $indexer then "selected=\"selected\"" else "UNKNOWN"#>$curIndexer[1]</option>
#end for
</select>
</td>
</tr>
#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
<tr>
<td class="col-checkbox">
<input type="checkbox" id="$show_id" class="dirCheck" checked=checked>
</td>
<td>
<label for="$show_id">
<span class="filepath#echo ('', ' red-text')[$curDir['highlight']]#">$curDir['path']</span>$curDir['name']
#echo ('', '<br />^ <span class="red-text">... (cannot add, this location is in use)</span>')[$curDir['highlight']]#
</label>
</td>
#if $curDir['existing_info'][1] and $indexer > 0
<td>
<a href="<%= anon_url(sickbeard.indexerApi(indexer).config['show_url'], curDir['existing_info'][0]) %>" target="_new">$curDir['existing_info'][1]</a>
</td>
#else
<td>?</td>
#end if
<td align="center">
<select name="indexer">
#for $curIndexer in $sickbeard.indexerApi().indexers.items()
<option value="$curIndexer[0]" #if $curIndexer[0] == $indexer then 'selected="selected"' else ''#>$curIndexer[1]</option>
#end for
</select>
</td>
</tr>
#end for
</tbody>
</tbody>
</table>
</tbody>
</table>

View file

@ -65,7 +65,7 @@
<input class="btn btn-inline" type="button" id="searchName" value="Search" />
</span>
<br />
<p style="margin:5px 0 15px"><b>*</b> SickGear supports english episodes. The language choice is used for fetching show data and episode filenames</p>
<p style="margin:5px 0 15px">Enter show name, TVDB ID, IMDb Url, or IMDb ID.&nbsp;&nbsp;<b>*</b>SickGear supports english, language is used for show/episode data</p>
<div id="searchResults" style="height: 100%"></div>
#end if
@ -116,4 +116,4 @@
</div></div>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -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);
});
});
});

View file

@ -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': '<span class="filepath">' + ek.ek(os.path.dirname, cur_path) + os.sep + '</span>' + 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:])