Add IMDb Watchlists to 'View' drop down on the 'Add from IMDb' page.

Add 5 decades of 'IMDb Popular' selections to 'View' drop down on 'Add from... Browse Shows'.
Add 'Other Services' to 'View' drop down on 'Add from... Browse Shows'.
Add enable, disable and delete public IMDb watchlists to Config/General/Interface with a default 'SickGear' list.
Change prevent duplicate show ids from presenting items on 'Add from... Browse Shows'.
Change add 'nocache' kwarg to helpers.getURL to facilitate non-cached requests.
This commit is contained in:
JackDandy 2016-04-19 23:28:44 +01:00
parent 5519fd7e13
commit 09741bbf8c
7 changed files with 410 additions and 28 deletions

View file

@ -55,6 +55,12 @@
* Fix syntax error causing renamer to error out
* Change storing metadata nfo vars from int to strings to resolve lxml type exceptions that don't occur with etree
* Add visual indicator for upcoming or started shows on Add Browse Shows
* Add IMDb Watchlists to 'View' drop down on the 'Add from IMDb' page
* Add 5 decades of 'IMDb Popular' selections to 'View' drop down on 'Add from... Browse Shows'
* Add 'Other Services' to 'View' drop down on 'Add from... Browse Shows'
* Add enable, disable and delete public IMDb watchlists to Config/General/Interface with a default 'SickGear' list
* Change prevent duplicate show ids from presenting items on 'Add from... Browse Shows'
* Change add 'nocache' kwarg to helpers.getURL to facilitate non-cached requests
### 0.11.11 (2016-04-05 19:20:00 UTC)

View file

@ -153,9 +153,9 @@
<label>
<span class="component-title">Show root directories</span>
<span class="component-desc">
<p>where the files of shows are located</p>
<p>where the files of shows are located</p>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_rootDirs.tmpl')
</span>
</span>
</label>
</div>
@ -266,8 +266,8 @@
</select>
#set $hidden = ' class="hidden"'
<span id="showlist_tagview_standard"#echo ('', $hidden)['standard' not in $sickbeard.SHOWLIST_TAGVIEW]#>that contains all shows (default)</span>
<span id="showlist_tagview_anime"#echo ('', $hidden)['anime' not in $sickbeard.SHOWLIST_TAGVIEW]#>two groups, the show list and anime</span>
<span id="showlist_tagview_custom"#echo ('', $hidden)['custom' not in $sickbeard.SHOWLIST_TAGVIEW]#>multiple custom<sup>1</sup> named groups and a "Show List"</span>
<span id="showlist_tagview_anime"#echo ('', $hidden)['anime' not in $sickbeard.SHOWLIST_TAGVIEW]#>two groups, the show list and anime</span>
<span id="showlist_tagview_custom"#echo ('', $hidden)['custom' not in $sickbeard.SHOWLIST_TAGVIEW]#>multiple custom<sup>1</sup> named groups and a "Show List"</span>
</span>
</label>
</div>
@ -278,7 +278,7 @@
<span class="component-desc">
<input type="text" name="show_tags" id="show_tags" value="$show_tags" class="form-control input-sm input300">
<span>comma separated names</span>
<p class="clear-left note">group shows to the order of this custom list (add shows to groups with <a href="/manage/">mass edit</a>)</p>
<p class="clear-left note">group shows to the order of this custom list (add shows to groups with <a href="/manage/">mass edit</a>)</p>
</span>
</label>
</div>
@ -303,6 +303,37 @@
</label>
</div>
<div class="field-pair">
<label for="imdb-accounts">
<span class="component-title">Public IMDb watchlists:</span>
#if not hasattr($sickbeard, 'IMDB_ACCOUNTS')#<span class="red-text">Restart SickGear to reveal new options here</span>#else#
<span class="component-desc">
<select id="imdb-accounts" class="pull-left form-control input-sm">
<option value="new" selected="selected">Add watchlist ...</option>
#for $i, $v in $enumerate($sickbeard.IMDB_ACCOUNTS)
#if not $i % 2
#set $id = $v
#else
<option value="$id">#echo '%s%s' % ($v, ('\'s', '')['your' == $v.replace('(Off) ', '').lower()])# list</option>
#end if
#end for
</select>
<input type="button" class="btn btn-inline" value="Delete" id="imdb-list-del" disabled="disabled" />
</span>
</label>
<label for="imdb-url">
<span class="component-title">&nbsp</span>
<span class="component-desc">
<input type="text" id="imdb-url" value="" class="form-control input-sm input250" />
<input type="button" class="btn btn-inline" value="Enable" id="imdb-list-onoff" />
<div class="clear-left">
<p><code>imdb.com/user/ur64552276</code> or <code>ur64552276</code> to <span id="view-list">view list</span><a class="hide" id="link-list" href="$sbRoot/home/addShows/watchlist_imdb?account=64552276">view list</a> at "Add from IMDb"
</p></div>
#end if
</span>
</label>
</div>
<div class="field-pair">
<label for="sort_article">
<span class="component-title">Sort with "The", "A", "An"</span>

View file

@ -6,7 +6,7 @@
#from sickbeard import sbdatetime
#from sickbeard.helpers import anon_url
##
#set global $title='Browse Shows'
#set global $title='Browse %s Shows' % $browse_type
#set global $header='Browse Shows'
#set global $sbPath='..'
#set global $topmenu='home'
@ -97,7 +97,7 @@
\$('#showfilter').on( 'change', function() {
var filterValue = this.value;
if (-1 == filterValue.indexOf('trakt')) {
if (-1 == filterValue.indexOf('trakt') && -1 == filterValue.indexOf('imdb') && -1 == filterValue.indexOf('default')) {
\$('#container').isotope({ filter: filterValue });
} else {
location = '$sbRoot/home/addShows/' + filterValue;
@ -118,18 +118,33 @@
#end if
<h1 style="margin-bottom:0" class="grey-text #echo '%s">%s' % $heading#</h1>
#if $all_shows or ($kwargs and $kwargs.get('show_header', None))
#set $mode = $kwargs and $kwargs.get('mode', '')
#if $all_shows or ($kwargs and $kwargs.get('show_header'))
<div class="pull-right" style="margin-top:-35px">
<span>Show:</span>
<span>View:</span>
<select id="showfilter" class="form-control form-control-inline input-sm">
#set $count_all_shows = len($all_shows)
#set $count_inlibrary = $all_shows_inlibrary
<option value="*" selected="selected">All<%= ' (%d)' % count_all_shows %></option>
<option value=".notinlibrary">Not In Library<%= ' (%d)' % (count_all_shows - count_inlibrary) %></option>
<option value=".inlibrary">In Library<%= ' (%d)' % count_inlibrary %></option>
#if $browse_type in ('IMDb', 'Trakt', 'AniDB')
<optgroup label="Other Services">
#if 'IMDb' == $browse_type
<option value="trakt_default">Trakt</option>
#elif 'Trakt' == $browse_type
<option value="imdb_default">IMDb</option>
#elif 'AniDB' == $browse_type
<option value="imdb_default">IMDb</option>
<option value="trakt_default">Trakt</option>
#end if
#if $sickbeard.USE_ANIDB and $browse_type in ('IMDb', 'Trakt')
<option value="anime_default">AniDB</option>
#end if
</optgroup>
#end if
#set $selected = ' class="selected"'
#if 'Trakt' == $browse_type
#set $mode = $kwargs and $kwargs.get('mode', None)
#set $selected = ' class="selected"'
<optgroup label="Trakt">
<option value="trakt_anticipated"#echo ('', selected)['anticipated' == $mode]#>Anticipating</option>
<option value="trakt_newseasons"#echo ('', selected)['newseasons' == $mode]#>New Seasons</option>
@ -151,7 +166,7 @@
<optgroup label="Trakt recommended">
#for $account in $sickbeard.TRAKT_ACCOUNTS
#if $sickbeard.TRAKT_ACCOUNTS[$account].active and $sickbeard.TRAKT_ACCOUNTS[$account].name
<option value="trakt_recommended?account=$account"#echo ('', selected)['recommended-%s' % $account == $mode]#>for $sickbeard.TRAKT_ACCOUNTS[$account].name</option>
<option value="trakt_recommended?account=$account"#echo ('', selected)[('recommended-%s' % $account) == $mode]#>for $sickbeard.TRAKT_ACCOUNTS[$account].name</option>
#end if
#end for
#else
@ -159,6 +174,30 @@
<option value="trakt_recommended?action=add">Enable Trakt here</option>
#end if
</optgroup>
#elif 'IMDb' == $browse_type
#set $periods = $kwargs and $kwargs.get('periods')
#if $periods
<optgroup label="IMDb Popular">
#for $i, $p in enumerate($periods)
#set $period='%s,%s' % ($p[0], $p[1])
<option value="popular_imdb?period=$period"#echo ('', selected)[('popular-%s' % $period) == $mode]#>#echo '%s - %s' % (($p[1], 'Current')[not $i], $p[0])#</option>
#end for
</optgroup>
#end if
#if not hasattr($sickbeard, 'IMDB_ACCOUNTS')#<optgroup label="Restart SickGear to reveal"><option>new options after restart</option></optgroup>#else#
<optgroup label="IMDb Watchlists">
#if any($sickbeard.IMDB_ACCOUNTS)
#for $i, $v in $enumerate($sickbeard.IMDB_ACCOUNTS)
#if not $i % 2
#set $id = $v
#elif not $v.startswith('(Off) ')
<option value="watchlist_imdb?account=$id"#echo ('', selected)[('watchlist-%s' % $id) == $mode]#>#echo '%s%s' % ($v, ('\'s', '')['your' == $v.replace('(Off) ', '').lower()])# list</option>
#end if
#end for
#end if
<option value="watchlist_imdb?action=add"><< Add lists >></option>
</optgroup>
#end if
#end if
</select>
@ -179,7 +218,7 @@
</select>
</div>
<h4 style="float:left;margin:0 0 0 2px">$browse_title</h4>
#if $kwargs and $kwargs.get('oldest', None):
#if $kwargs and $kwargs.get('oldest'):
<div class="grey-text" style="clear:both;margin-left:2px;font-size:0.85em">
First aired from $kwargs['oldest'] until $kwargs['newest']
</div>
@ -190,7 +229,7 @@
#if $all_shows
#for $this_show in $all_shows:
#set $title_html = $this_show['title'].replace('"', '&quot;').replace("'", '&#39;')
#if 'newseasons' == $kwargs.get('mode', '')
#if 'newseasons' == $mode
#set $overview = '%s: %s' % (
('Season %s' % $this_show['episode_season'], 'Brand-new')[1 == $this_show['episode_season']],
($this_show['overview'], $this_show['episode_overview'])[any($this_show['episode_overview']) and 1 != $this_show['episode_season']])
@ -204,7 +243,7 @@
<a class="browse-image" href="<%= anon_url(this_show['url_src_db']) %>" target="_blank"
title="<span style='color: rgb(66, 139, 202)'>$re.sub(r'(?m)\s+\((?:19|20)\d\d\)\s*$', '', $title_html)</span>#if $this_show['genres']#<br /><div style='font-weight:bold'>(<em>$this_show['genres']</em>)</div>#end if#
<p style='margin:0 0 2px'>#echo re.sub(r'([,\.!][^,\.!]*?)$', '...', re.sub(r'([!\?\.])(?=\w)', r'\1 ', $overview))#</p>
<p><span style='font-weight:bold;font-size:0.9em;color:#888'><em>#if $kwargs and 'newseasons' == $kwargs.get('mode', None)#Air#else#First air#end if##echo ('s', 'ed')[$this_show['when_past']]#: $this_show['premiered_str']</em></span></p>
<p><span style='font-weight:bold;font-size:0.9em;color:#888'><em>#if $kwargs and 'newseasons' == $mode#Air#else#First air#end if##echo ('s', 'ed')[$this_show['when_past']]#: $this_show['premiered_str']</em></span></p>
<span style='float:right'>Click for more at <span class='boldest'>$browse_type</span></span>">
#if 'poster' in $this_show['images']:
#set $image = $this_show['images']['poster']['thumb']
@ -243,15 +282,15 @@
</div>
#end for
</div>
#if $kwargs and $kwargs.get('footnote', None):
#if $kwargs and $kwargs.get('footnote'):
<div>
$kwargs['footnote']
</div>
#end if
#else
<div class="show-card" style="width:100%; margin-top:20px">
<div class="show-card" style="width:100%; margin-top:20px; padding:20px">
<p class="red-text">
#if $kwargs and $kwargs.get('error_msg', None):
#if $kwargs and $kwargs.get('error_msg'):
$kwargs['error_msg']
#else
$browse_type API did not return results, this can happen from time to time.

View file

@ -30,6 +30,126 @@ $(document).ready(function () {
}
});
var idSelect = '#imdb-accounts', idDel = '#imdb-list-del', idInput = '#imdb-url', idOnOff = '#imdb-list-onoff',
sel = 'selected', opt = 'option', selOpt = [opt, sel].join(':'),
elDropDown = $(idSelect), elDel = $(idDel), elInput = $(idInput), elOnOff = $(idOnOff);
function accId() {return elDropDown.find(selOpt).val();}
function nameList() {return elDropDown.find(selOpt).text();}
function isAdd() {return 'new' === accId();}
function isOff() {return 0 == nameList().indexOf('(Off) ');}
function warnMessage(msg) { elInput.addClass('warning').prop('title', msg); }
function all(state) {$([idSelect, idDel, idInput, idOnOff].join()).prop('disabled', 'on' == state ? !1 : !0)}
function setOnOff() {elOnOff.val(isAdd() || isOff() ? 'Enable' : 'Disable');}
function setLink() {
var idView = '#view-list', idLink = '#link-list';
return $([idView, idLink].join()).removeClass() &&
((isAdd() || isOff()) && $(idLink).addClass('hide') || $(idView).addClass('hide')) &&
(!isOff() && $(idLink)
.attr('href', sbRoot + '/home/addShows/watchlist_imdb?account=' + accId())
.attr('title', 'View ' + nameList()));
}
function defaultControls() {
elDel.prop('disabled', isAdd());
elInput.removeClass('warning')
.val(!isAdd() && accId() || '')
.prop('title', isAdd() ? '' : 'Select Add. Use Delete or Disable')
.prop('readonly', !isAdd());
setOnOff();
setLink();
}
function populateSelect(jsonData) {
/** @namespace response.accounts */
var response = $.parseJSON(jsonData);
if ('Success' !== response.result) {
warnMessage(response.result);
return !1;
}
elDropDown.find(opt).slice(1).remove();
var i, l, accounts = response.accounts, options = elDropDown.get(0).options;
for (i = 0, l = accounts.length; i < l; i = i + 2) {
options[options.length] = new Option(accounts[i + 1] +
(0 == accounts[i + 1].replace('(Off) ', '').toLowerCase().indexOf('your') ? '' : '\'s') + ' list', accounts[i]);
if (0 <= $.trim(elInput.val()).indexOf(accounts[i])) {
elDropDown.find(opt).prop(sel, !1);
elDropDown.find('option[value="' + accounts[i] + '"]').prop(sel, sel);
elInput.val(accounts[i]);
elInput.prop('title', 'Select Add. Use Delete or Disable');
setOnOff();
}
}
return !0;
}
elDropDown.change(function() {
defaultControls();
});
elDel.on('click', function(e) {
all('off');
$.confirm({
'title' : 'Remove the "' + nameList().replace('\'s', '').replace(' list', '') + '" IMDb Watchlist',
'message' : 'Are you sure you want to remove <span class="footerhighlight">' + nameList() + '</span> ?<br /><br />',
'buttons' : {
'Yes' : {
'class' : 'green',
'action': function() {
all('off');
$.get(sbRoot + '/home/addShows/watchlist_imdb', {
'action': elDel.val().toLowerCase(),
'select': accId()})
.done(function(response) {
all('on'); setControls(!populateSelect(response), !1); setOnOff(); })
.fail(function() {
all('on'); setControls(!0, 'Invalid ID'); setOnOff(); });
}
},
'No' : {
'class' : 'red',
'action': function() { e.preventDefault(); all('on'); defaultControls();}
}
}
});
});
elOnOff.on('click', function(e) {
var strList = $.trim(elInput.val());
elInput.removeClass('warning');
if (!strList) {
warnMessage('Missing IMDb list Id or URL');
} else {
all('off');
var params = {'action': elOnOff.val().toLowerCase()};
if ('enable' == params.action)
params.input = strList;
else
params.select = accId();
$.get(sbRoot + '/home/addShows/watchlist_imdb', params)
.done(function(data) { setControls(!populateSelect(data), !1); })
.fail(function() { setControls(!0, 'Failed to load list'); });
}
});
function setControls(resetSelect, message) {
all('on');
if (resetSelect) {
if (message)
warnMessage(message);
var addList = '[value="new"]';
elDropDown.find(opt).not(addList).prop(sel, !1);
elDropDown.find(opt + addList).prop(sel, sel);
}
elDel.prop('disabled', isAdd());
elInput.prop('readonly', !isAdd());
setLink()
}
var ui_update_trim_zero = (function () {
var secs = ('00' + new Date().getSeconds().toString()).slice(-2),
elSecs = $('#trim_info_seconds'),
@ -193,15 +313,15 @@ function fetch_branches() {
}
function add_option_to_pulls(text) {
option = $('<option>');
var option = $('<option>');
option.attr('value', text[1]);
option.html(text[0]);
option.appendTo('#pullRequestVersion');
}
function add_option_to_branches(text) {
option = $('<option>');
var option = $('<option>');
option.attr('value', text);
option.html(text);
option.appendTo('#branchVersion');
}
}

View file

@ -170,6 +170,9 @@ INDEXER_TIMEOUT = None
SCENE_DEFAULT = False
ANIME_DEFAULT = False
USE_IMDB_INFO = True
IMDB_ACCOUNTS = []
IMDB_DEFAULT_LIST_ID = '64552276'
IMDB_DEFAULT_LIST_NAME = 'SickGear'
PROVIDER_ORDER = []
NAMING_MULTI_EP = False
@ -535,7 +538,7 @@ def initialize(consoleLogging=True):
AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
ANIME_DEFAULT, NAMING_ANIME, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \
SCENE_DEFAULT, BACKLOG_DAYS, SEARCH_UNAIRED, ANIME_TREAT_AS_HDTV, \
COOKIE_SECRET, USE_IMDB_INFO, DISPLAY_BACKGROUND, DISPLAY_BACKGROUND_TRANSPARENT, DISPLAY_ALL_SEASONS, \
COOKIE_SECRET, USE_IMDB_INFO, IMDB_ACCOUNTS, DISPLAY_BACKGROUND, DISPLAY_BACKGROUND_TRANSPARENT, DISPLAY_ALL_SEASONS, \
SHOW_TAGS, DEFAULT_SHOW_TAG, SHOWLIST_TAGVIEW
if __INITIALIZED__:
@ -602,6 +605,7 @@ def initialize(consoleLogging=True):
GUI_NAME = check_setting_str(CFG, 'GUI', 'gui_name', 'slick')
DEFAULT_HOME = check_setting_str(CFG, 'GUI', 'default_home', 'home')
USE_IMDB_INFO = bool(check_setting_int(CFG, 'GUI', 'use_imdb_info', 1))
IMDB_ACCOUNTS = CFG.get('GUI', []).get('imdb_accounts', [IMDB_DEFAULT_LIST_ID, IMDB_DEFAULT_LIST_NAME])
HOME_SEARCH_FOCUS = bool(check_setting_int(CFG, 'General', 'home_search_focus', HOME_SEARCH_FOCUS))
SORT_ARTICLE = bool(check_setting_int(CFG, 'General', 'sort_article', 0))
FUZZY_DATING = bool(check_setting_int(CFG, 'GUI', 'fuzzy_dating', 0))
@ -1798,6 +1802,7 @@ def save_config():
new_config['GUI']['theme_name'] = THEME_NAME
new_config['GUI']['default_home'] = DEFAULT_HOME
new_config['GUI']['use_imdb_info'] = int(USE_IMDB_INFO)
new_config['GUI']['imdb_accounts'] = IMDB_ACCOUNTS
new_config['GUI']['fuzzy_dating'] = int(FUZZY_DATING)
new_config['GUI']['trim_zero'] = int(TRIM_ZERO)
new_config['GUI']['date_preset'] = DATE_PRESET

View file

@ -1120,8 +1120,12 @@ def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=N
# request session
if None is session:
session = requests.session()
cache_dir = sickbeard.CACHE_DIR or _getTempDir()
session = CacheControl(sess=session, cache=caches.FileCache(os.path.join(cache_dir, 'sessions')))
if not kwargs.get('nocache'):
cache_dir = sickbeard.CACHE_DIR or _getTempDir()
session = CacheControl(sess=session, cache=caches.FileCache(os.path.join(cache_dir, 'sessions')))
else:
del(kwargs['nocache'])
# request session headers
req_headers = {'User-Agent': USER_AGENT, 'Accept-Encoding': 'gzip,deflate'}

View file

@ -2526,6 +2526,168 @@ class NewHomeAddShows(Home):
return
return self.new_show('|'.join(['', '', '', indexer_id or showName]), use_show_name=True, is_anime=True)
@staticmethod
def watchlist_config(**kwargs):
if not isinstance(sickbeard.IMDB_ACCOUNTS, type([])):
sickbeard.IMDB_ACCOUNTS = list(sickbeard.IMDB_ACCOUNTS)
accounts = dict(map(None, *[iter(sickbeard.IMDB_ACCOUNTS)] * 2))
if 'enable' == kwargs.get('action'):
account_id = re.findall('\d{6,32}', kwargs.get('input', ''))
if not account_id:
return json.dumps({'result': 'Fail: Invalid IMDb ID'})
acc_id = account_id[0]
url = 'http://www.imdb.com/user/ur%s/watchlist' % acc_id + \
'/_ajax?sort=date_added,desc&mode=detail&page=1&title_type=tvSeries%2CtvEpisode&ref_=wl_vm_dtl'
html = helpers.getURL(url, nocache=True)
try:
list_name = re.findall('(?i)<h1[^>]+>(.*)\s+Watchlist</h1>', html)[0].replace('\'s', '')
accounts[acc_id] = list_name or 'noname'
except:
return json.dumps({'result': 'Fail: No list found with id: %s' % acc_id})
else:
acc_id = kwargs.get('select', '')
if acc_id not in accounts:
return json.dumps({'result': 'Fail: Unknown IMDb ID'})
if 'disable' == kwargs.get('action'):
accounts[acc_id] = '(Off) %s' % accounts[acc_id].replace('(Off) ', '')
else:
del accounts[acc_id]
gears = [[k, v] for k, v in accounts.iteritems() if 'sickgear' in v.lower()]
if gears:
del accounts[gears[0][0]]
yours = [[k, v] for k, v in accounts.iteritems() if 'your' == v.replace('(Off) ', '').lower()]
if yours:
del accounts[yours[0][0]]
sickbeard.IMDB_ACCOUNTS = [x for tup in sorted(list(accounts.items()), key=lambda t: t[1]) for x in tup]
if gears:
sickbeard.IMDB_ACCOUNTS.insert(0, gears[0][1])
sickbeard.IMDB_ACCOUNTS.insert(0, gears[0][0])
if yours:
sickbeard.IMDB_ACCOUNTS.insert(0, yours[0][1])
sickbeard.IMDB_ACCOUNTS.insert(0, yours[0][0])
sickbeard.save_config()
return json.dumps({'result': 'Success', 'accounts': sickbeard.IMDB_ACCOUNTS})
def watchlist_imdb(self, *args, **kwargs):
if 'add' == kwargs.get('action'):
return self.redirect('/config/general/#core-component-group2')
if kwargs.get('action') in ('delete', 'enable', 'disable'):
return self.watchlist_config(**kwargs)
browse_type = 'IMDb'
filtered = []
footnote = None
start_year, end_year = (datetime.date.today().year - 10, datetime.date.today().year + 1)
periods = [(start_year, end_year)] + [(x-10, x) for x in range(start_year, start_year-40, -10)]
accounts = dict(map(None, *[iter(sickbeard.IMDB_ACCOUNTS)]*2))
acc_id, list_name = (sickbeard.IMDB_DEFAULT_LIST_ID, sickbeard.IMDB_DEFAULT_LIST_NAME) if \
0 == sickbeard.helpers.tryInt(kwargs.get('account')) or \
kwargs.get('account') not in accounts.keys() or \
accounts.get(kwargs.get('account'), '').startswith('(Off) ') else \
(kwargs.get('account'), accounts.get(kwargs.get('account')))
list_name += ('\'s', '')['your' == list_name.replace('(Off) ', '').lower()]
url = 'http://www.imdb.com/user/ur%s/watchlist' % acc_id
url_data = '/_ajax?sort=date_added,desc&mode=detail&page=1&title_type=tvSeries%2CtvEpisode&ref_=wl_vm_dtl'
url_ui = '?mode=detail&page=1&sort=date_added,desc&title_type=tvSeries%2CtvEpisode&ref_=wl_ref_typ'
html = helpers.getURL(url + url_data)
if html:
img_size = re.compile(r'(?im)(V1[^XY]+([XY]))(\d+)([^\d]+)(\d+)([^\d]+)(\d+)([^\d]+)(\d+)([^\d]+)(\d+)(.*?)$')
imdb_id = re.compile(r'(?i).*(tt\d+).*')
with BS4Parser(html, features=['html5lib', 'permissive']) as soup:
show_list = soup.find('div', {'class': 'lister-list'})
shows = [] if not show_list else show_list.find_all('div', {'class': 'mode-detail'})
oldest, newest, oldest_dt, newest_dt = None, None, 9999999, 0
for show in shows:
try:
url_path = show.select('h3.lister-item-header a[href*=title]')[0]['href'].strip('/')
ids = dict(imdb=imdb_id.sub(r'\1', url_path))
first_aired = show.select('h3.lister-item-header span.lister-item-year')
year = None if not len(first_aired) else re.sub(r'.*(\d{4}).*', r'\1', first_aired[0].get_text())
dt_ordinal = 0
if year:
dt = dateutil.parser.parse('01-01-%s' % year)
dt_ordinal = dt.toordinal()
if dt_ordinal < oldest_dt:
oldest_dt = dt_ordinal
oldest = year
if dt_ordinal > newest_dt:
newest_dt = dt_ordinal
newest = year
genres = show.select('span.genre')
images = {}
img = show.select('div.lister-item-image img')
overview = '' if not show.find('p', '') else show.find('p', '').get_text().strip()
rating = show.find('meta', attrs={'itemprop': 'ratingValue'})
rating = None is not rating and rating.get('content') or ''
voting = show.find('meta', attrs={'itemprop': 'ratingCount'})
voting = None is not voting and voting.get('content') or ''
if len(img):
img_uri = img[0].get('loadlate')
match = img_size.search(img_uri)
if match and 'tv_series.gif' not in img_uri and 'nopicture' not in img_uri:
scale = lambda low1, high1: int((float(450) / high1) * low1)
high = int(max([match.group(9), match.group(11)]))
scaled = [scale(x, high) for x in [(int(match.group(n)), high)[high == int(match.group(n))] for n in 3, 5, 7, 9, 11]]
parts = [match.group(1), match.group(4), match.group(6), match.group(8), match.group(10), match.group(12)]
img_uri = img_uri.replace(match.group(), ''.join([str(y) for x in map(None, parts, scaled) for y in x if y is not None]))
path = ek.ek(os.path.abspath, ek.ek(os.path.join, sickbeard.CACHE_DIR, 'images', 'imdb'))
helpers.make_dirs(path)
file_name = ek.ek(os.path.basename, img_uri)
cached_name = ek.ek(os.path.join, path, file_name)
if not ek.ek(os.path.isfile, cached_name):
helpers.download_file(img_uri, cached_name)
images = dict(poster=dict(thumb='cache/images/imdb/%s' % file_name))
filtered.append(dict(
premiered=dt_ordinal,
premiered_str=year or 'No year',
when_past=dt_ordinal < datetime.datetime.now().toordinal(), # air time not poss. 16.11.2015
genres='No genre yet' if not len(genres) else genres[0].get_text().strip().lower().replace(' |', ','),
ids=ids,
images=images,
overview='No overview yet' if not len(overview) else self.encode_html(overview[:250:].strip()),
rating=0 if not len(rating) else int(helpers.tryFloat(rating) * 10),
title=show.select('h3.lister-item-header a[href*=title]')[0].get_text().strip(),
url_src_db='http://www.imdb.com/%s/' % url_path,
votes=0 if not len(voting) else helpers.tryInt(voting)))
tvshow = filter(lambda x: x.imdbid == ids['imdb'], sickbeard.showList)[0]
src = ((None, 'tvrage')[INDEXER_TVRAGE == tvshow.indexer], 'tvdb')[INDEXER_TVDB == tvshow.indexer]
if src:
filtered[-1]['ids'][src] = tvshow.indexerid
filtered[-1]['url_' + src] = '%s%s' % (sickbeard.indexerApi(tvshow.indexer).config['show_url'], tvshow.indexerid)
except (AttributeError, TypeError, KeyError, IndexError):
continue
kwargs.update(dict(oldest=oldest, newest=newest, start_year=start_year))
if len(filtered):
footnote = 'Note; Some images on this page may be cropped at source: <a target="_blank" href="%s">%s watchlist at IMDb</a>' % (helpers.anon_url(url + url_ui), list_name)
elif None is not show_list:
kwargs['show_header'] = True
kwargs['error_msg'] = 'No TV titles in the <a target="_blank" href="%s">%s watchlist at IMDb</a>' % (helpers.anon_url(url + url_ui), list_name)
kwargs.update(dict(footnote=footnote, mode='watchlist-%s' % acc_id, periods=periods))
return self.browse_shows(browse_type, '%s IMDb Watchlist' % list_name, filtered, **kwargs)
def popular_imdb(self, *args, **kwargs):
browse_type = 'IMDb'
@ -2533,6 +2695,15 @@ class NewHomeAddShows(Home):
filtered = []
footnote = None
start_year, end_year = (datetime.date.today().year - 10, datetime.date.today().year + 1)
periods = [(start_year, end_year)] + [(x-10, x) for x in range(start_year, start_year-40, -10)]
start_year_in, end_year_in = [helpers.tryInt(x) for x in (('0,0', kwargs.get('period'))[
',' in kwargs.get('period', '')]).split(',')]
if 1900 < start_year_in < 2050 and 2050 > end_year_in > 1900:
start_year, end_year = (start_year_in, end_year_in)
mode = 'popular-%s,%s' % (start_year, end_year)
url = 'http://www.imdb.com/search/title?at=0&sort=moviemeter&title_type=tv_series&year=%s,%s' % (start_year, end_year)
html = helpers.getURL(url)
if html:
@ -2598,7 +2769,8 @@ class NewHomeAddShows(Home):
rating=0 if not len(rating) else int(helpers.tryFloat(rating[0].get_text()) * 10),
title=tr.select('td.title a')[0].get_text().strip(),
url_src_db='http://www.imdb.com/%s/' % url_path,
votes=0 if not len(voting) else vote_value.sub(r'\1\2', voting[0].get('title'))))
votes=0 if not len(voting) else helpers.tryInt(
vote_value.sub(r'\1\2', voting[0].get('title')), 'TBA')))
tvshow = filter(lambda x: x.imdbid == ids['imdb'], sickbeard.showList)[0]
src = ((None, 'tvrage')[INDEXER_TVRAGE == tvshow.indexer], 'tvdb')[INDEXER_TVDB == tvshow.indexer]
@ -2608,7 +2780,7 @@ class NewHomeAddShows(Home):
except (AttributeError, TypeError, KeyError, IndexError):
continue
kwargs.update(dict(oldest=oldest, newest=newest))
kwargs.update(dict(oldest=oldest, newest=newest, mode=mode, periods=periods))
if len(filtered):
footnote = 'Note; Some images on this page may be cropped at source: <a target="_blank" href="%s">IMDb</a>' % helpers.anon_url(url)
@ -2803,11 +2975,12 @@ class NewHomeAddShows(Home):
t.submenu = self.HomeMenu()
t.browse_type = browse_type
t.browse_title = browse_title
t.all_shows = shows
t.all_shows = []
t.kwargs = kwargs
dedupe = []
t.all_shows_inlibrary = 0
for item in t.all_shows:
for item in shows:
item['show_id'] = ''
for index, tvdb in enumerate(['tvdb', 'tvrage']):
try:
@ -2827,6 +3000,10 @@ class NewHomeAddShows(Home):
if not item['show_id'] and 'tt' in item['ids'].get('imdb', ''):
item['show_id'] = item['ids']['imdb']
if item['show_id'] not in dedupe:
dedupe.append(item['show_id'])
t.all_shows.append(item)
return t.respond()
def existing_shows(self, *args, **kwargs):