- #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.
diff --git a/gui/slick/js/config.js b/gui/slick/js/config.js
index a7e6a942..5b01a099 100644
--- a/gui/slick/js/config.js
+++ b/gui/slick/js/config.js
@@ -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 ? ',
+ '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 = $('');
+ var option = $(' ');
option.attr('value', text[1]);
option.html(text[0]);
option.appendTo('#pullRequestVersion');
}
function add_option_to_branches(text) {
- option = $(' ');
+ var option = $(' ');
option.attr('value', text);
option.html(text);
option.appendTo('#branchVersion');
-}
\ No newline at end of file
+}
diff --git a/lib/imdb/__init__.py b/lib/imdb/__init__.py
index 0cdc9650..32019cb5 100644
--- a/lib/imdb/__init__.py
+++ b/lib/imdb/__init__.py
@@ -6,7 +6,7 @@ a person from the IMDb database.
It can fetch data through different media (e.g.: the IMDb web pages,
a SQL database, etc.)
-Copyright 2004-2014 Davide Alberani
+Copyright 2004-2015 Davide Alberani
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
__all__ = ['IMDb', 'IMDbError', 'Movie', 'Person', 'Character', 'Company',
'available_access_systems']
-__version__ = VERSION = '5.0'
+__version__ = VERSION = '5.1dev20160106'
# Import compatibility module (importing it is enough).
import _compat
diff --git a/lib/imdb/imdbpy.cfg b/lib/imdb/imdbpy.cfg
index 68b30538..b67fbbe5 100644
--- a/lib/imdb/imdbpy.cfg
+++ b/lib/imdb/imdbpy.cfg
@@ -29,7 +29,7 @@
[imdbpy]
## Default.
-accessSystem = httpThin
+#accessSystem = http
## Optional (options common to every data access system):
# Activate adult searches (on, by default).
@@ -69,7 +69,7 @@ accessSystem = httpThin
## Set the threshold for logging messages.
# Can be one of "debug", "info", "warning", "error", "critical" (default:
# "warning").
-loggingLevel = debug
+#loggingLevel = debug
## Path to a configuration file for the logging facility;
# see: http://docs.python.org/library/logging.html#configuring-logging
diff --git a/lib/imdb/locale/imdbpy-de.po b/lib/imdb/locale/imdbpy-de.po
index c0585b92..ee3112b1 100644
--- a/lib/imdb/locale/imdbpy-de.po
+++ b/lib/imdb/locale/imdbpy-de.po
@@ -1,12 +1,13 @@
# Gettext message file for imdbpy
# Translators:
-# Ioan, 2013
+# Nils Welzk, 2013
+# Raphael, 2014
msgid ""
msgstr ""
"Project-Id-Version: IMDbPY\n"
"POT-Creation-Date: 2010-03-18 14:35+0000\n"
-"PO-Revision-Date: 2013-11-20 11:07+0000\n"
-"Last-Translator: Ioan\n"
+"PO-Revision-Date: 2014-10-21 15:24+0000\n"
+"Last-Translator: Raphael\n"
"Language-Team: German (http://www.transifex.com/projects/p/imdbpy/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,11 +21,11 @@ msgstr ""
# Default: Actor
msgid "actor"
-msgstr ""
+msgstr "Schauspieler"
# Default: Actress
msgid "actress"
-msgstr ""
+msgstr "Schauspielerin"
# Default: Adaption
msgid "adaption"
@@ -32,7 +33,7 @@ msgstr ""
# Default: Additional information
msgid "additional-information"
-msgstr ""
+msgstr "zusätzliche Information"
# Default: Admissions
msgid "admissions"
@@ -48,7 +49,7 @@ msgstr ""
# Default: Akas
msgid "akas"
-msgstr ""
+msgstr "Pseudonüme"
# Default: Akas from release info
msgid "akas-from-release-info"
@@ -56,7 +57,7 @@ msgstr ""
# Default: All products
msgid "all-products"
-msgstr ""
+msgstr "Alle Produkte"
# Default: Alternate language version of
msgid "alternate-language-version-of"
@@ -68,7 +69,7 @@ msgstr ""
# Default: Amazon reviews
msgid "amazon-reviews"
-msgstr ""
+msgstr "Amazon Rezensionen"
# Default: Analog left
msgid "analog-left"
@@ -100,7 +101,7 @@ msgstr ""
# Default: Art director
msgid "art-director"
-msgstr ""
+msgstr "Art Director"
# Default: Article
msgid "article"
@@ -112,7 +113,7 @@ msgstr ""
# Default: Aspect ratio
msgid "aspect-ratio"
-msgstr ""
+msgstr "Seitenverhältnis"
# Default: Assigner
msgid "assigner"
@@ -132,7 +133,7 @@ msgstr ""
# Default: Audio quality
msgid "audio-quality"
-msgstr ""
+msgstr "Audio Qualität"
# Default: Award
msgid "award"
@@ -188,7 +189,7 @@ msgstr "Kosten"
# Default: Business
msgid "business"
-msgstr ""
+msgstr "Geschäft"
# Default: By arrangement with
msgid "by-arrangement-with"
@@ -220,7 +221,7 @@ msgstr ""
# Default: Cast
msgid "cast"
-msgstr ""
+msgstr "Besetzung"
# Default: Casting department
msgid "casting-department"
@@ -236,23 +237,23 @@ msgstr ""
# Default: Category
msgid "category"
-msgstr ""
+msgstr "Kategorie"
# Default: Certificate
msgid "certificate"
-msgstr ""
+msgstr "Zertifikat"
# Default: Certificates
msgid "certificates"
-msgstr ""
+msgstr "Zertifikate"
# Default: Certification
msgid "certification"
-msgstr ""
+msgstr "Bescheinigung"
# Default: Channel
msgid "channel"
-msgstr ""
+msgstr "Kanal"
# Default: Character
msgid "character"
@@ -372,7 +373,7 @@ msgstr ""
# Default: Description
msgid "description"
-msgstr ""
+msgstr "Beschreibung"
# Default: Dialogue intellegibility
msgid "dialogue-intellegibility"
@@ -396,7 +397,7 @@ msgstr ""
# Default: Distributors
msgid "distributors"
-msgstr ""
+msgstr "Händler"
# Default: Dvd
msgid "dvd"
@@ -452,7 +453,7 @@ msgstr "Episoden"
# Default: Episodes rating
msgid "episodes-rating"
-msgstr ""
+msgstr "Episoden Bewertung"
# Default: Essays
msgid "essays"
@@ -464,7 +465,7 @@ msgstr ""
# Default: Faqs
msgid "faqs"
-msgstr ""
+msgstr "FAQs"
# Default: Feature
msgid "feature"
@@ -488,19 +489,19 @@ msgstr ""
# Default: Filmography
msgid "filmography"
-msgstr ""
+msgstr "Filmografie"
# Default: Followed by
msgid "followed-by"
-msgstr ""
+msgstr "gefolgt von"
# Default: Follows
msgid "follows"
-msgstr ""
+msgstr "folgt"
# Default: For
msgid "for"
-msgstr ""
+msgstr "für"
# Default: Frequency response
msgid "frequency-response"
@@ -508,7 +509,7 @@ msgstr ""
# Default: From
msgid "from"
-msgstr ""
+msgstr "von"
# Default: Full article link
msgid "full-article-link"
@@ -524,7 +525,7 @@ msgstr ""
# Default: Genres
msgid "genres"
-msgstr ""
+msgstr "Genres"
# Default: Goofs
msgid "goofs"
@@ -540,7 +541,7 @@ msgstr ""
# Default: Headshot
msgid "headshot"
-msgstr ""
+msgstr "Portrait"
# Default: Height
msgid "height"
@@ -556,15 +557,15 @@ msgstr ""
# Default: Interview
msgid "interview"
-msgstr ""
+msgstr "Interview"
# Default: Interviews
msgid "interviews"
-msgstr ""
+msgstr "Interviews"
# Default: Introduction
msgid "introduction"
-msgstr ""
+msgstr "Vorstellung"
# Default: Item
msgid "item"
@@ -596,7 +597,7 @@ msgstr "Sprachen"
# Default: Laserdisc
msgid "laserdisc"
-msgstr ""
+msgstr "Laserdisc"
# Default: Laserdisc title
msgid "laserdisc-title"
@@ -624,7 +625,7 @@ msgstr "Literatur"
# Default: Locations
msgid "locations"
-msgstr ""
+msgstr "Standorte"
# Default: Long imdb canonical name
msgid "long-imdb-canonical-name"
@@ -708,11 +709,11 @@ msgstr ""
# Default: Nick names
msgid "nick-names"
-msgstr ""
+msgstr "Spitznamen"
# Default: Notes
msgid "notes"
-msgstr ""
+msgstr "Anmerkungen"
# Default: Novel
msgid "novel"
@@ -720,7 +721,7 @@ msgstr ""
# Default: Number
msgid "number"
-msgstr ""
+msgstr "Zahl"
# Default: Number of chapter stops
msgid "number-of-chapter-stops"
@@ -800,7 +801,7 @@ msgstr ""
# Default: Plot
msgid "plot"
-msgstr "Inhalt"
+msgstr "Handlung"
# Default: Plot outline
msgid "plot-outline"
@@ -824,7 +825,7 @@ msgstr ""
# Default: Producer
msgid "producer"
-msgstr ""
+msgstr "Produzent"
# Default: Production companies
msgid "production-companies"
@@ -864,15 +865,15 @@ msgstr ""
# Default: Quote
msgid "quote"
-msgstr ""
+msgstr "Zitat"
# Default: Quotes
msgid "quotes"
-msgstr ""
+msgstr "Zitate"
# Default: Rating
msgid "rating"
-msgstr ""
+msgstr "Bewertung"
# Default: Recommendations
msgid "recommendations"
@@ -896,11 +897,11 @@ msgstr ""
# Default: Release date
msgid "release-date"
-msgstr ""
+msgstr "Veröffentlichungsdatum"
# Default: Release dates
msgid "release-dates"
-msgstr ""
+msgstr "Veröffentlichungstermine"
# Default: Remade as
msgid "remade-as"
@@ -908,27 +909,27 @@ msgstr ""
# Default: Remake of
msgid "remake-of"
-msgstr ""
+msgstr "Remake von"
# Default: Rentals
msgid "rentals"
-msgstr ""
+msgstr "Leigebühr"
# Default: Result
msgid "result"
-msgstr ""
+msgstr "Ergebnis"
# Default: Review
msgid "review"
-msgstr ""
+msgstr "Kritik"
# Default: Review author
msgid "review-author"
-msgstr ""
+msgstr "Kritik Autor"
# Default: Review kind
msgid "review-kind"
-msgstr ""
+msgstr "Kritik Art"
# Default: Runtime
msgid "runtime"
@@ -1096,7 +1097,7 @@ msgstr ""
# Default: Soundtrack
msgid "soundtrack"
-msgstr ""
+msgstr "Soundtrack"
# Default: Spaciality
msgid "spaciality"
@@ -1116,43 +1117,43 @@ msgstr ""
# Default: Spin off
msgid "spin-off"
-msgstr ""
+msgstr "Nebenprodukt"
# Default: Spin off from
msgid "spin-off-from"
-msgstr ""
+msgstr "Nebenprodukt von"
# Default: Spoofed in
msgid "spoofed-in"
-msgstr ""
+msgstr "Parodiert in"
# Default: Spoofs
msgid "spoofs"
-msgstr ""
+msgstr "Parodie"
# Default: Spouse
msgid "spouse"
-msgstr ""
+msgstr "Gattin"
# Default: Status of availablility
msgid "status-of-availablility"
-msgstr ""
+msgstr "Verfügbarkeitsstatus"
# Default: Studio
msgid "studio"
-msgstr ""
+msgstr "Studio"
# Default: Studios
msgid "studios"
-msgstr ""
+msgstr "Studios"
# Default: Stunt performer
msgid "stunt-performer"
-msgstr ""
+msgstr "Stunt-Darsteller"
# Default: Stunts
msgid "stunts"
-msgstr ""
+msgstr "Stunts"
# Default: Subtitles
msgid "subtitles"
@@ -1160,19 +1161,19 @@ msgstr "Untertitel"
# Default: Supplement
msgid "supplement"
-msgstr ""
+msgstr "Ergänzung"
# Default: Supplements
msgid "supplements"
-msgstr ""
+msgstr "Ergänzungen"
# Default: Synopsis
msgid "synopsis"
-msgstr ""
+msgstr "Zusammenfassung"
# Default: Taglines
msgid "taglines"
-msgstr ""
+msgstr "Slogan"
# Default: Tech info
msgid "tech-info"
@@ -1188,7 +1189,7 @@ msgstr "Zeit"
# Default: Title
msgid "title"
-msgstr ""
+msgstr "Titel"
# Default: Titles in this product
msgid "titles-in-this-product"
@@ -1200,11 +1201,11 @@ msgstr ""
# Default: Top 250 rank
msgid "top-250-rank"
-msgstr ""
+msgstr "Top 250 platzierung"
# Default: Trade mark
msgid "trade-mark"
-msgstr ""
+msgstr "Warenzeichen"
# Default: Transportation department
msgid "transportation-department"
@@ -1212,7 +1213,7 @@ msgstr ""
# Default: Trivia
msgid "trivia"
-msgstr ""
+msgstr "Nichtigkeiten"
# Default: Tv
msgid "tv"
@@ -1220,7 +1221,7 @@ msgstr "TV"
# Default: Under license from
msgid "under-license-from"
-msgstr ""
+msgstr "lizensiert von"
# Default: Unknown link
msgid "unknown-link"
@@ -1256,19 +1257,19 @@ msgstr ""
# Default: Video quality
msgid "video-quality"
-msgstr ""
+msgstr "Video Qualität"
# Default: Video standard
msgid "video-standard"
-msgstr ""
+msgstr "Video Standart"
# Default: Visual effects
msgid "visual-effects"
-msgstr ""
+msgstr "Visuelle Effekte"
# Default: Votes
msgid "votes"
-msgstr ""
+msgstr "Stimmen"
# Default: Votes distribution
msgid "votes-distribution"
@@ -1284,11 +1285,11 @@ msgstr ""
# Default: With
msgid "with"
-msgstr ""
+msgstr "mit"
# Default: Writer
msgid "writer"
-msgstr "Schreiber"
+msgstr "Autor"
# Default: Written by
msgid "written-by"
diff --git a/lib/imdb/locale/imdbpy-fr.po b/lib/imdb/locale/imdbpy-fr.po
index c4509c99..f40012c1 100644
--- a/lib/imdb/locale/imdbpy-fr.po
+++ b/lib/imdb/locale/imdbpy-fr.po
@@ -1,13 +1,14 @@
# Gettext message file for imdbpy
# Translators:
-# RainDropR , 2013
-# Stéphane Aulery, 2012
+# lukophron, 2014
+# Rajaa Gutknecht , 2013
+# lkppo, 2012
msgid ""
msgstr ""
"Project-Id-Version: IMDbPY\n"
"POT-Creation-Date: 2010-03-18 14:35+0000\n"
-"PO-Revision-Date: 2013-11-20 11:07+0000\n"
-"Last-Translator: RainDropR \n"
+"PO-Revision-Date: 2014-10-08 02:52+0000\n"
+"Last-Translator: lukophron\n"
"Language-Team: French (http://www.transifex.com/projects/p/imdbpy/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -33,11 +34,11 @@ msgstr "adaptation"
# Default: Additional information
msgid "additional-information"
-msgstr ""
+msgstr "information-additionnelle"
# Default: Admissions
msgid "admissions"
-msgstr ""
+msgstr "admissions"
# Default: Agent address
msgid "agent-address"
diff --git a/lib/imdb/parser/http/__init__.py b/lib/imdb/parser/http/__init__.py
index 16f8518d..a3001a08 100644
--- a/lib/imdb/parser/http/__init__.py
+++ b/lib/imdb/parser/http/__init__.py
@@ -726,6 +726,10 @@ class IMDbHTTPAccessSystem(IMDbBase):
cont = self._retrieve(self.urls['person_main'] % personID + 'bio')
return self.pProxy.bio_parser.parse(cont, getRefs=self._getRefs)
+ def get_person_resume(self, personID):
+ cont = self._retrieve(self.urls['person_main'] % personID + 'resume')
+ return self.pProxy.resume_parser.parse(cont, getRefs=self._getRefs)
+
def get_person_awards(self, personID):
cont = self._retrieve(self.urls['person_main'] % personID + 'awards')
return self.pProxy.person_awards_parser.parse(cont)
diff --git a/lib/imdb/parser/http/movieParser.py b/lib/imdb/parser/http/movieParser.py
index a203b0d9..174d73f8 100644
--- a/lib/imdb/parser/http/movieParser.py
+++ b/lib/imdb/parser/http/movieParser.py
@@ -226,7 +226,7 @@ class DOMHTMLMovieParser(DOMParserBase):
Attribute(key="countries",
path="./h5[starts-with(text(), " \
"'Countr')]/../div[@class='info-content']//text()",
- postprocess=makeSplitter('|')),
+ postprocess=makeSplitter('|')),
Attribute(key="language",
path="./h5[starts-with(text(), " \
"'Language')]/..//text()",
@@ -234,7 +234,7 @@ class DOMHTMLMovieParser(DOMParserBase):
Attribute(key='color info',
path="./h5[starts-with(text(), " \
"'Color')]/..//text()",
- postprocess=makeSplitter('Color:')),
+ postprocess=makeSplitter('|')),
Attribute(key='sound mix',
path="./h5[starts-with(text(), " \
"'Sound Mix')]/..//text()",
@@ -462,6 +462,8 @@ class DOMHTMLMovieParser(DOMParserBase):
del data['other akas']
if nakas:
data['akas'] = nakas
+ if 'color info' in data:
+ data['color info'] = [x.replace('Color:', '', 1) for x in data['color info']]
if 'runtimes' in data:
data['runtimes'] = [x.replace(' min', u'')
for x in data['runtimes']]
@@ -1177,7 +1179,7 @@ class DOMHTMLCriticReviewsParser(DOMParserBase):
path="//div[@class='article']/div[@class='see-more']/a",
attrs=Attribute(key='metacritic url',
path="./@href")) ]
-
+
class DOMHTMLOfficialsitesParser(DOMParserBase):
"""Parser for the "official sites", "external reviews", "newsgroup
reviews", "miscellaneous links", "sound clips", "video clips" and
@@ -1534,7 +1536,7 @@ class DOMHTMLSeasonEpisodesParser(DOMParserBase):
'').strip()
episode_title = episode.get('title', '').strip()
episode_plot = episode.get('plot', '')
- if not (episode_nr and episode_id and episode_title):
+ if not (episode_nr is not None and episode_id and episode_title):
continue
ep_obj = Movie(movieID=episode_id, title=episode_title,
accessSystem=self._as, modFunct=self._modFunct)
diff --git a/lib/imdb/parser/http/personParser.py b/lib/imdb/parser/http/personParser.py
index 9261a4da..64b1916d 100644
--- a/lib/imdb/parser/http/personParser.py
+++ b/lib/imdb/parser/http/personParser.py
@@ -204,7 +204,7 @@ class DOMHTMLBioParser(DOMParserBase):
_birth_attrs = [Attribute(key='birth date',
path={
'day': "./a[starts-with(@href, " \
- "'/date/')]/text()",
+ "'/search/name?birth_monthday=')]/text()",
'year': "./a[starts-with(@href, " \
"'/search/name?birth_year=')]/text()"
},
@@ -215,7 +215,7 @@ class DOMHTMLBioParser(DOMParserBase):
_death_attrs = [Attribute(key='death date',
path={
'day': "./a[starts-with(@href, " \
- "'/date/')]/text()",
+ "'/search/name?death_monthday=')]/text()",
'year': "./a[starts-with(@href, " \
"'/search/name?death_date=')]/text()"
},
@@ -326,6 +326,107 @@ class DOMHTMLBioParser(DOMParserBase):
return data
+class DOMHTMLResumeParser(DOMParserBase):
+ """Parser for the "resume" page of a given person.
+ The page should be provided as a string, as taken from
+ the akas.imdb.com server. The final result will be a
+ dictionary, with a key for every relevant section.
+
+ Example:
+ resumeparser = DOMHTMLResumeParser()
+ result = resumeparser.parse(resume_html_string)
+ """
+ _defGetRefs = True
+
+ extractors = [
+ Extractor(label='info',
+ group="//div[@class='section_box']",
+ group_key="./h3/text()",
+ group_key_normalize=lambda x: x.lower().replace(' ', '_'),
+ path="./ul[@class='resume_section_multi_list']//li",
+ attrs=Attribute(key=None,
+ multi=True,
+ path={
+ 'title': ".//b//text()",
+ 'desc': ".//text()",
+ },
+ postprocess=lambda x: (x.get('title'), x.get('desc').strip().replace('\n', ' ')))),
+ Extractor(label='other_info',
+ group="//div[@class='section_box']",
+ group_key="./h3/text()",
+ group_key_normalize=lambda x: x.lower().replace(' ', '_'),
+ path="./ul[@class='_imdbpy']//li",
+ attrs=Attribute(key=None,
+ multi=True,
+ path=".//text()",
+ postprocess=lambda x: x.strip().replace('\n', ' '))),
+ Extractor(label='credits',
+ group="//div[@class='section_box']",
+ group_key="./h3/text()",
+ group_key_normalize=lambda x: x.lower().replace(' ', '_'),
+ path="./table[@class='credits']//tr",
+ attrs=Attribute(key=None,
+ multi=True,
+ path={
+ '0':".//td[1]//text()",
+ '1':".//td[2]//text()",
+ '2':".//td[3]//text()",
+ },
+ postprocess=lambda x: [x.get('0'),x.get('1'),x.get('2')])),
+ Extractor(label='mini_info',
+ path="//div[@class='center']",
+ attrs=Attribute(key='mini_info',
+ path=".//text()",
+ postprocess=lambda x: x.strip().replace('\n', ' '))),
+ Extractor(label='name',
+ path="//div[@class='center']/h1[@id='preview_user_name']",
+ attrs=Attribute(key='name',
+ path=".//text()",
+ postprocess=lambda x: x.strip().replace('\n', ' '))),
+ Extractor(label='resume_bio',
+ path="//div[@id='resume_rendered_html']//p",
+ attrs=Attribute(key='resume_bio',
+ multi=True,
+ path=".//text()")),
+
+ ]
+
+ preprocessors = [
+ (re.compile('()', re.I), r'\1'),
+ ]
+
+ def postprocess_data(self, data):
+
+ for key in data.keys():
+ if data[key] == '':
+ del data[key]
+ if key in ('mini_info', 'name', 'resume_bio'):
+ if key == 'resume_bio':
+ data[key] = "".join(data[key]).strip()
+ continue
+ if len(data[key][0]) == 3:
+ for item in data[key]:
+ item[:] = [x for x in item if not x == None]
+ continue
+
+ if len(data[key][0]) == 2:
+ new_key = {}
+ for item in data[key]:
+ if item[0] == None:
+ continue
+ if ':' in item[0]:
+ if item[1].replace(item[0], '')[1:].strip() == '':
+ continue
+ new_key[item[0].strip().replace(':', '')] = item[1].replace(item[0], '')[1:].strip()
+ else:
+ new_key[item[0]] = item[1]
+ data[key] = new_key
+
+ new_data = {}
+ new_data['resume'] = data
+ return new_data
+
+
class DOMHTMLOtherWorksParser(DOMParserBase):
"""Parser for the "other works" and "agent" pages of a given person.
The page should be provided as a string, as taken from
@@ -502,6 +603,7 @@ from movieParser import DOMHTMLNewsParser
_OBJECTS = {
'maindetails_parser': ((DOMHTMLMaindetailsParser,), None),
'bio_parser': ((DOMHTMLBioParser,), None),
+ 'resume_parser': ((DOMHTMLResumeParser,), None),
'otherworks_parser': ((DOMHTMLOtherWorksParser,), None),
#'agent_parser': ((DOMHTMLOtherWorksParser,), {'kind': 'agent'}),
'person_officialsites_parser': ((DOMHTMLOfficialsitesParser,), None),
diff --git a/lib/imdb/parser/http/topBottomParser.py b/lib/imdb/parser/http/topBottomParser.py
index f0f29509..1b8bb9f0 100644
--- a/lib/imdb/parser/http/topBottomParser.py
+++ b/lib/imdb/parser/http/topBottomParser.py
@@ -7,7 +7,7 @@ E.g.:
http://akas.imdb.com/chart/top
http://akas.imdb.com/chart/bottom
-Copyright 2009 Davide Alberani
+Copyright 2009-2015 Davide Alberani
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -43,14 +43,15 @@ class DOMHTMLTop250Parser(DOMParserBase):
def _init(self):
self.extractors = [Extractor(label=self.label,
- path="//div[@id='main']//table//tr",
+ path="//div[@id='main']//div[1]//div//table//tbody//tr",
attrs=Attribute(key=None,
multi=True,
- path={self.ranktext: "./td[1]//text()",
- 'rating': "./td[2]//text()",
- 'title': "./td[3]//text()",
- 'movieID': "./td[3]//a/@href",
- 'votes': "./td[4]//text()"
+ path={self.ranktext: "./td[2]//text()",
+ 'rating': "./td[3]//strong//text()",
+ 'title': "./td[2]//a//text()",
+ 'year': "./td[2]//span//text()",
+ 'movieID': "./td[2]//a/@href",
+ 'votes': "./td[3]//strong/@title"
}))]
def postprocess_data(self, data):
@@ -72,12 +73,16 @@ class DOMHTMLTop250Parser(DOMParserBase):
if theID in seenIDs:
continue
seenIDs.append(theID)
- minfo = analyze_title(d['title'])
+ minfo = analyze_title(d['title']+" "+d['year'])
try: minfo[self.ranktext] = int(d[self.ranktext].replace('.', ''))
except: pass
if 'votes' in d:
- try: minfo['votes'] = int(d['votes'].replace(',', ''))
- except: pass
+ try:
+ votes = d['votes'].replace(' votes','')
+ votes = votes.split(' based on ')[1]
+ minfo['votes'] = int(votes.replace(',', ''))
+ except:
+ pass
if 'rating' in d:
try: minfo['rating'] = float(d['rating'])
except: pass
diff --git a/lib/imdb/parser/http/utils.py b/lib/imdb/parser/http/utils.py
index 031a4d3a..8b4e17e3 100644
--- a/lib/imdb/parser/http/utils.py
+++ b/lib/imdb/parser/http/utils.py
@@ -441,12 +441,6 @@ class DOMParserBase(object):
self._useModule = useModule
nrMods = len(useModule)
_gotError = False
-
- # Force warnings.warn() to omit the source code line in the message
- formatwarning_orig = warnings.formatwarning
- warnings.formatwarning = lambda message, category, filename, lineno, line=None: \
- formatwarning_orig(message, category, filename, lineno, line='')
-
for idx, mod in enumerate(useModule):
mod = mod.strip().lower()
try:
diff --git a/lib/imdb/utils.py b/lib/imdb/utils.py
index f468efd4..a506722d 100644
--- a/lib/imdb/utils.py
+++ b/lib/imdb/utils.py
@@ -639,11 +639,14 @@ def analyze_company_name(name, stripNotes=False):
o_name = name
name = name.strip()
country = None
- if name.endswith(']'):
- idx = name.rfind('[')
- if idx != -1:
- country = name[idx:]
- name = name[:idx].rstrip()
+ if name.startswith('['):
+ name = re.sub('[!@#$\(\)\[\]]', '', name)
+ else:
+ if name.endswith(']'):
+ idx = name.rfind('[')
+ if idx != -1:
+ country = name[idx:]
+ name = name[:idx].rstrip()
if not name:
raise IMDbParserError('invalid name: "%s"' % o_name)
result = {'name': name}
@@ -957,7 +960,7 @@ def _tag4TON(ton, addAccessSystem=False, _containerOnly=False):
crl = [crl]
for cr in crl:
crTag = cr.__class__.__name__.lower()
- crValue = cr['long imdb name']
+ crValue = cr.get('long imdb name') or u''
crValue = _normalizeValue(crValue)
crID = cr.getID()
if crID is not None:
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 868e66cc..48953d75 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -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
diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py
index 6eaea47e..78840870 100644
--- a/sickbeard/helpers.py
+++ b/sickbeard/helpers.py
@@ -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'}
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index b9941416..5fe83015 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -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)]+>(.*)\s+Watchlist ', 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: %s watchlist at IMDb ' % (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 %s watchlist at IMDb ' % (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: IMDb ' % 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):