diff --git a/.travis.yml b/.travis.yml index 6d85ba9e19dafdf3b94eac202e71ab15d9eecf5d..9e41afd1d0fedac9d35c5910cf73850290d98adc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: python python: - - 2.6 - 2.7 +sudo: false + branches: except: - master diff --git a/SickBeard.py b/SickBeard.py index 2ee3659706e1d7b46a869a33ff6133a8973bf6b3..0955ca7dbf77f67bf8ff4395bf4899ff482c936f 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -147,6 +147,30 @@ class SickRage(object): help_msg += " --noresize Prevent resizing of the banner/posters even if PIL is installed\n" return help_msg + + def fix_clients_nonsense(): + + files = ["sickbeard/clients/download_station.py", + "sickbeard/clients/utorrent.py", + "sickbeard/clients/generic.py", + "sickbeard/clients/qbittorrent.py", + "sickbeard/clients/transmission.py", + "sickbeard/clients/deluge.py", + "sickbeard/clients/rtorrent.py" + ] + + for file in files: + file = ek.ek(os.path.join, sickbeard.PROG_DIR, file) + try: + if ek.ek(os.path.exists, file): + ek.ek(os.remove, file) + except: + pass + try: + if ek.ek(os.path.exists, file + "c"): + ek.ek(os.remove, file + "c") + except: + pass def start(self): # do some preliminary stuff @@ -317,6 +341,9 @@ class SickRage(object): # Get PID sickbeard.PID = os.getpid() + + # Fix clients old files + self.fix_clients_nonsense() # Build from the DB to start with self.loadShowsFromDB() diff --git a/gui/slick/images/flags/za.png b/gui/slick/images/flags/za.png new file mode 100644 index 0000000000000000000000000000000000000000..c9341107300bc8a3449174e181e0ae483f2d912e Binary files /dev/null and b/gui/slick/images/flags/za.png differ diff --git a/gui/slick/images/network/arena.png b/gui/slick/images/network/arena.png new file mode 100644 index 0000000000000000000000000000000000000000..4966f47ca66cfa2bddf4e752594470581eff53ab Binary files /dev/null and b/gui/slick/images/network/arena.png differ diff --git a/gui/slick/images/network/fyi.png b/gui/slick/images/network/fyi.png new file mode 100644 index 0000000000000000000000000000000000000000..c46c4d35c409b1cf98ff333da3fc7b373f4cc113 Binary files /dev/null and b/gui/slick/images/network/fyi.png differ diff --git a/gui/slick/images/network/soho.png b/gui/slick/images/network/soho.png new file mode 100644 index 0000000000000000000000000000000000000000..82e4f728e12eec62f902423a0512c82d7bf66f51 Binary files /dev/null and b/gui/slick/images/network/soho.png differ diff --git a/gui/slick/interfaces/default/IRC.tmpl b/gui/slick/interfaces/default/IRC.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..528f5822f3477f5543dacb24ee9aad20c12daaa0 --- /dev/null +++ b/gui/slick/interfaces/default/IRC.tmpl @@ -0,0 +1,9 @@ +#import sickbeard +#from sickbeard.common import * + +#import os.path +#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl") + +<iframe id="extFrame" src="https://kiwiirc.com/client/irc.freenode.net/?nick=srforums|?&theme=basic#sickrage" width="100%" height="500" frameBorder="0" style="border: 1px black solid;"></iframe> + +#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_bottom.tmpl") diff --git a/gui/slick/interfaces/default/apiBuilder.tmpl b/gui/slick/interfaces/default/apiBuilder.tmpl index e7b0454f48fe45a3d6cd205ec1e44fd8cf24d906..42397e4567361f7287e285d658bdf7f20558db65 100644 --- a/gui/slick/interfaces/default/apiBuilder.tmpl +++ b/gui/slick/interfaces/default/apiBuilder.tmpl @@ -65,6 +65,7 @@ addList("Command", "Show.AddNew", "?cmd=show.addnew", "show.addnew", "", "", "ac addList("Command", "Show.Cache", "?cmd=show.cache", "indexerid", "", "", "action"); addList("Command", "Show.Delete", "?cmd=show.delete", "show.delete", "", "", "action"); addList("Command", "Show.GetBanner", "?cmd=show.getbanner", "indexerid", "", "", "action"); +addList("Command", "Show.GetFanArt", "?cmd=show.getfanart", "indexerid", "", "", "action"); addList("Command", "Show.GetNetworkLogo", "?cmd=show.getnetworklogo", "indexerid", "", "", "action"); addList("Command", "Show.GetPoster", "?cmd=show.getposter", "indexerid", "", "", "action"); addList("Command", "Show.GetQuality", "?cmd=show.getquality", "indexerid", "", "", "action"); diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index 0686a4386a2010aa0f21fbfe25bce7ff92056fb4..ddb12a1b64b31c868ec06880bd630958c98673c5 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -1589,7 +1589,7 @@ </label> <label> <span class="component-title"> </span> - <span class="component-desc">Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' page</span> + <span class="component-desc">Name(slug) of List on Trakt for blacklisting show on 'Add Trending Show' & 'Add Recommended Shows' pages</span> </label> </div> <div class="field-pair"> diff --git a/gui/slick/interfaces/default/config_subtitles.tmpl b/gui/slick/interfaces/default/config_subtitles.tmpl index 75e4434aeedb6fb6faa813af3b5e3ceab0be80d1..7e3cf3e7894663edd1f9eacd491000169efcd655 100644 --- a/gui/slick/interfaces/default/config_subtitles.tmpl +++ b/gui/slick/interfaces/default/config_subtitles.tmpl @@ -124,7 +124,33 @@ <p><b>Warning: </b>this will ignore <u>all</u> embedded subtitles for every video file!</p> </span> </label> - </div> + </div> + <div class="field-pair"> + <label class="nocheck"> + <span class="component-title">Extra Scripts</span> + <input type="text" name="subtitles_extra_scripts" value="<%='|'.join(sickbeard.SUBTITLES_EXTRA_SCRIPTS)%>" class="form-control input-sm input350" /> + </label> + <label class="nocheck"> + <span class="component-title"> </span> + <span class="component-desc"><b>NOTE:</b></span> + </label> + <label class="nocheck"> + <span class="component-title"> </span> + <span class="component-desc"> + <ul> + <li>See <a href="https://github.com/SiCKRAGETV/SickRage/wiki/Subtitle%20Scripts"><font color='red'><b>Wiki</b></font></a> for a script arguments description.</li> + <li>Additional scripts separated by <b>|</b>.</li> + <li>Scripts are called after each episode has searched and downloaded subtitles.</li> + <li>For any scripted languages, include the interpreter executable before the script. See the following example:</li> + <ul> + <li>For Windows: <pre>C:\Python27\pythonw.exe C:\Script\test.py</pre></li> + <li>For Linux: <pre>python /Script/test.py</pre></li> + </ul> + </ul> + </span> + </label> + </div> + <br/><input type="submit" class="btn config_submitter" value="Save Changes" /><br/> </div> </fieldset> diff --git a/gui/slick/interfaces/default/displayShow.tmpl b/gui/slick/interfaces/default/displayShow.tmpl index c6638d170832d8b1d56813cbeb6b894419d1c70e..b3c9f04766989d7b1cb5f202cafb7dc9e7311dcd 100644 --- a/gui/slick/interfaces/default/displayShow.tmpl +++ b/gui/slick/interfaces/default/displayShow.tmpl @@ -547,9 +547,10 @@ #if $epResult['location'] #set $filename = $epResult['location'] #for $rootDir in $sickbeard.ROOT_DIRS.split('|') - #if $rootDir.startswith('/') - #set $filename = ntpath.basename($filename) + #if not $rootDir.startswith('/') + #set $filename = $filename.replace('\\','\\\\') #end if + #set $filename = ntpath.basename($filename) #end for $filename #end if diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index 39c35fdcb5f49b8db460166bd306d23274bad575..3c2bce53b60caea47066456b74654a009334fd43 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -164,6 +164,9 @@ <ul class="nav navbar-nav navbar-right"> <li id="NAVnews"> <a href="$sbRoot/news/">News</a> + </li> + <li id="NAVnews"> + <a href="$sbRoot/IRC/">IRC</a> </li> <li id="NAVhome"> <a href="$sbRoot/home/">Shows</a> diff --git a/gui/slick/js/apibuilder.js b/gui/slick/js/apibuilder.js index 48dafdca45d6be44befae965fe1d75ff7f8bec78..cdf0e730f40f8c99e545870a1b7480ca43dacb47 100644 --- a/gui/slick/js/apibuilder.js +++ b/gui/slick/js/apibuilder.js @@ -9,6 +9,7 @@ var _disable_empty_list=false; var _hide_empty_list=false; +var _image_commands=['?cmd=show.getbanner', '?cmd=show.getfanart', '?cmd=show.getnetworklogo', '?cmd=show.getposter'] function goListGroup(apikey, L7, L6, L5, L4, L3, L2, L1){ var html, GlobalOptions = ""; @@ -25,8 +26,8 @@ function goListGroup(apikey, L7, L6, L5, L4, L3, L2, L1){ } }); - // handle the show.getposter / show.getbanner differently as they return an image and not json - if (L1 == "?cmd=show.getposter" || L1 == "?cmd=show.getbanner") { + // Some commands return an image instead of JSON + if ($.inArray(L1, _image_commands) > -1) { var imgcache = sbRoot + "/api/" + apikey + "/" + L1 + L2 + GlobalOptions; html = imgcache + '<br/><br/><img src="' + sbRoot + '/images/loading16.gif" id="imgcache">'; $('#apiResponse').html(html); diff --git a/readme.md b/readme.md index 932b67dfde74db3e106da2251a28da7085e76839..8f93e86656b32a17216667b4edcf479b336c3fb5 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ Automatic Video Library Manager for TV Shows. It watches for new episodes of you -[Mobile](http://imgur.com/a/WPyG6) ## Dependencies - To run SickRage from source you will need Python 2.6+, Cheetah 2.1.0+, and PyOpenSSL + To run SickRage from source you will need Python 2.7.x, Cheetah 2.1.0+, and PyOpenSSL ## Forums Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index a13af38a53f883ef4ef5edfd8b54153ced579a07..e75df4eae5cbc735f5e628650ac5cf56cdf99b02 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -119,7 +119,7 @@ NOTIFY_ON_UPDATE = False CUR_COMMIT_HASH = None BRANCH = '' -GIT_RESET = False +GIT_RESET = True GIT_REMOTE = '' GIT_REMOTE_URL = '' CUR_COMMIT_BRANCH = '' @@ -500,7 +500,7 @@ TIMEZONE_DISPLAY = None THEME_NAME = None POSTER_SORTBY = None POSTER_SORTDIR = None -FILTER_ROW = False +FILTER_ROW = True USE_SUBTITLES = False SUBTITLES_LANGUAGES = [] @@ -511,6 +511,7 @@ SUBTITLES_HISTORY = False EMBEDDED_SUBTITLES_ALL = False SUBTITLES_FINDER_FREQUENCY = 1 SUBTITLES_MULTI = False +SUBTITLES_EXTRA_SCRIPTS = [] USE_FAILED_DOWNLOADS = False DELETE_FAILED = False @@ -583,7 +584,7 @@ def initialize(consoleLogging=True): GUI_NAME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, COMING_EPS_LAYOUT, COMING_EPS_SORT, COMING_EPS_DISPLAY_PAUSED, COMING_EPS_MISSED_RANGE, DISPLAY_FILESIZE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, FILTER_ROW, \ POSTER_SORTBY, POSTER_SORTDIR, \ METADATA_WDTV, METADATA_TIVO, METADATA_MEDE8ER, IGNORE_WORDS, REQUIRE_WORDS, CALENDAR_UNPROTECTED, NO_RESTART, CREATE_MISSING_SHOW_DIRS, \ - ADD_SHOWS_WO_DIR, USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_SERVICES_LIST, SUBTITLES_SERVICES_ENABLED, SUBTITLES_HISTORY, SUBTITLES_FINDER_FREQUENCY, SUBTITLES_MULTI, EMBEDDED_SUBTITLES_ALL, subtitlesFinderScheduler, \ + ADD_SHOWS_WO_DIR, USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_SERVICES_LIST, SUBTITLES_SERVICES_ENABLED, SUBTITLES_HISTORY, SUBTITLES_FINDER_FREQUENCY, SUBTITLES_MULTI, EMBEDDED_SUBTITLES_ALL, SUBTITLES_EXTRA_SCRIPTS, subtitlesFinderScheduler, \ USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, PROXY_INDEXERS, \ AUTOPOSTPROCESSER_FREQUENCY, SHOWUPDATE_HOUR, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ @@ -650,7 +651,7 @@ def initialize(consoleLogging=True): logger.log('Unable to setup github properly, github will not be available. Error: {0}'.format(ex(e)),logger.WARNING) # git reset on update - GIT_RESET = bool(check_setting_int(CFG, 'General', 'git_reset', 0)) + GIT_RESET = bool(check_setting_int(CFG, 'General', 'git_reset', 1)) # current git branch BRANCH = check_setting_str(CFG, 'General', 'branch', '') @@ -1101,6 +1102,9 @@ def initialize(consoleLogging=True): SUBTITLES_FINDER_FREQUENCY = check_setting_int(CFG, 'Subtitles', 'subtitles_finder_frequency', 1) SUBTITLES_MULTI = bool(check_setting_int(CFG, 'Subtitles', 'subtitles_multi', 1)) + SUBTITLES_EXTRA_SCRIPTS = [x.strip() for x in check_setting_str(CFG, 'Subtitles', 'subtitles_extra_scripts', '').split('|') if + x.strip()] + USE_FAILED_DOWNLOADS = bool(check_setting_int(CFG, 'FailedDownloads', 'use_failed_downloads', 0)) DELETE_FAILED = bool(check_setting_int(CFG, 'FailedDownloads', 'delete_failed', 0)) @@ -1149,7 +1153,7 @@ def initialize(consoleLogging=True): TIMEZONE_DISPLAY = check_setting_str(CFG, 'GUI', 'timezone_display', 'network') POSTER_SORTBY = check_setting_str(CFG, 'GUI', 'poster_sortby', 'name') POSTER_SORTDIR = check_setting_int(CFG, 'GUI', 'poster_sortdir', 1) - FILTER_ROW = bool(check_setting_int(CFG, 'GUI', 'filter_row', 0)) + FILTER_ROW = bool(check_setting_int(CFG, 'GUI', 'filter_row', 1)) DISPLAY_ALL_SEASONS = bool(check_setting_int(CFG, 'General', 'display_all_seasons', 1)) # initialize NZB and TORRENT providers @@ -2094,6 +2098,7 @@ def save_config(): new_config['Subtitles']['embedded_subtitles_all'] = int(EMBEDDED_SUBTITLES_ALL) new_config['Subtitles']['subtitles_finder_frequency'] = int(SUBTITLES_FINDER_FREQUENCY) new_config['Subtitles']['subtitles_multi'] = int(SUBTITLES_MULTI) + new_config['Subtitles']['subtitles_extra_scripts'] = '|'.join(SUBTITLES_EXTRA_SCRIPTS) new_config['FailedDownloads'] = {} new_config['FailedDownloads']['use_failed_downloads'] = int(USE_FAILED_DOWNLOADS) diff --git a/sickbeard/common.py b/sickbeard/common.py index bccb2acf60c9eaa5b84a3453cda6b558acf08cb9..8946ad6b6ea3e1d045d45f6ac9a1b05c65ed0b19 100644 --- a/sickbeard/common.py +++ b/sickbeard/common.py @@ -22,9 +22,30 @@ import platform import re import uuid +from random import shuffle + +SPOOF_USER_AGENT = False + +# If some provider has an issue with functionality of SR, other than user agents, it's best to come talk to us rather than block. +# It is no different than us going to a provider if we have questions or issues. Be a team player here. +# This is disabled, was only added for testing, and has no config.ini or web ui setting. To enable, set SPOOF_USER_AGENT = True +user_agents = ['Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36' + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36' + 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0' + 'Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0' + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A' + 'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25' + 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko' + 'Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko' + ] + INSTANCE_ID = str(uuid.uuid1()) USER_AGENT = ('SickRage/(' + platform.system() + '; ' + platform.release() + '; ' + INSTANCE_ID + ')') +if SPOOF_USER_AGENT: + shuffle(user_agents) + USER_AGENT = user_agents[0] + mediaExtensions = ['avi', 'mkv', 'mpg', 'mpeg', 'wmv', 'ogm', 'mp4', 'iso', 'img', 'divx', 'm2ts', 'm4v', 'ts', 'flv', 'f4v', diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py index afe0cfd7e1bb89b17720e33c597230f3e6fe85bb..2a09c9ad10355469d3bbe4894db7b1f289c7e75f 100644 --- a/sickbeard/databases/mainDB.py +++ b/sickbeard/databases/mainDB.py @@ -42,6 +42,7 @@ class MainSanityCheck(db.DBSanityCheck): self.fix_episode_statuses() self.fix_invalid_airdates() self.fix_subtitles_codes() + self.fix_show_nfo_lang() def fix_duplicate_shows(self, column='indexer_id'): @@ -203,6 +204,8 @@ class MainSanityCheck(db.DBSanityCheck): self.connection.action("UPDATE tv_episodes SET subtitles = ?, subtitles_lastsearch = ? WHERE episode_id = ?;", [','.join(langs), datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), sqlResult['episode_id']]) + def fix_show_nfo_lang(self): + self.connection.action("UPDATE tv_shows SET lang = '' WHERE lang = 0 or lang = '0'") def backupDatabase(version): logger.log(u"Backing up database before upgrade") diff --git a/sickbeard/logger.py b/sickbeard/logger.py index b991c9f6be4e3e7c30b5189c03709f4e819bb0bb..0172c6856c079bfd1d70e8b03bfe8f5adadc4ddf 100644 --- a/sickbeard/logger.py +++ b/sickbeard/logger.py @@ -135,8 +135,6 @@ class Logger(object): # pass exception information if debugging enabled if level == ERROR: - #Replace the SSL error with a link to information about how to fix it. - message = re.sub(r'error \[Errno 1\] _ssl.c:\d{3}: error:\d{8}:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error', r'See: http://git.io/vJrkM', message) self.logger.exception(message, *args, **kwargs) classes.ErrorViewer.add(classes.UIError(message)) @@ -194,8 +192,11 @@ class Logger(object): title_Error = str(curError.title) if not len(title_Error) or title_Error == 'None': title_Error = re.match("^[A-Z0-9\-\[\] :]+::\s*(.*)$", ek.ss(str(curError.message))).group(1) - if len(title_Error) > 1024: - title_Error = title_Error[0:1024] + + # if len(title_Error) > (1024 - len(u"[APP SUBMITTED]: ")): + # 1000 just looks better than 1007 and adds some buffer + if len(title_Error) > 1000: + title_Error = title_Error[0:1000] except Exception as e: self.log("Unable to get error title : " + sickbeard.exceptions.ex(e), ERROR) diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index cf792484dcb51009080fd07c63858906c1e843ad..f3e2d4df55c907855bc510ff64539a0b35201613 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -708,12 +708,12 @@ class GenericMetadata(): logger.log(u"Image already exists, not downloading", logger.DEBUG) return False + image_dir = ek.ek(os.path.dirname, image_path) + if not image_data: - logger.log(u"Unable to retrieve image, skipping", logger.WARNING) + logger.log(u"Unable to retrieve image to save in %s, skipping" % ek.ss(image_dir), logger.WARNING) return False - image_dir = ek.ek(os.path.dirname, image_path) - try: if not ek.ek(os.path.isdir, image_dir): logger.log(u"Metadata dir didn't exist, creating it at " + image_dir, logger.DEBUG) diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 51f53ddfddd1deac11699be524513e75c19e7317..c66022ea08aacdade63c001d2ae49be50e8ab4cf 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -912,7 +912,7 @@ class PostProcessor(object): # try to find out if we have enough space to perform the copy or move action. if not helpers.isFileLocked(self.file_path, False): - if not verify_freespace(self.file_path, ek.ek(os.path.dirname, ep_obj.show._location), [ep_obj] + ep_obj.relatedEps): + if not verify_freespace(self.file_path, ep_obj.show._location, [ep_obj] + ep_obj.relatedEps): self._log("Not enough space to continue PP, exiting") return False else: diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py index 6fcf33dcd4905f0d048fe8684a56f9e010c8faeb..32a1d0f5bd087e263994de02e01df13b8448a9d3 100644 --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -216,7 +216,6 @@ def getDefaultNewznabProviders(): #name|url|key|catIDs|enabled|search_mode|search_fallback|enable_daily|enable_backlog return 'NZB.Cat|https://nzb.cat/||5030,5040,5010|0|eponly|1|1|1!!!' + \ 'NZBGeek|https://api.nzbgeek.info/||5030,5040|0|eponly|0|0|0!!!' + \ - 'Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0!!!' + \ 'NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0!!!' + \ 'Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0' diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index a9f18435cb0e4eb8069c19b8d26da7f805c06ffc..501331fd7e20c365278d256451914fcc213f06d1 100644 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -279,6 +279,9 @@ class NewznabProvider(generic.NZBProvider): results = [] offset = total = 0 + if 'lolo.sickbeard.com' in self.url and params['maxage'] < 33: + params['maxage'] = 33 + while (total >= offset): search_url = self.url + 'api?' + urllib.urlencode(params) @@ -379,6 +382,9 @@ class NewznabCache(tvcache.TVCache): "maxage": 4, } + if 'lolo.sickbeard.com' in self.provider.url: + params['maxage'] = 33 + if self.provider.needs_auth and self.provider.key: params['apikey'] = self.provider.key diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py index 29f27f0608b777409a6d9100ca7f56bbb0a7c01d..df0c9475cfb287145f6cd54c71aa967f5f827dea 100644 --- a/sickbeard/show_queue.py +++ b/sickbeard/show_queue.py @@ -216,14 +216,14 @@ class QueueItemAdd(ShowQueueItem): if sickbeard.TRAKT_USE_ROLLING_DOWNLOAD and sickbeard.USE_TRAKT: self.paused = sickbeard.TRAKT_ROLLING_ADD_PAUSED - # Process add show in priority - self.priority = generic_queue.QueuePriorities.HIGH - self.show = None # this will initialize self.show to None ShowQueueItem.__init__(self, ShowQueueActions.ADD, self.show) + # Process add show in priority + self.priority = generic_queue.QueuePriorities.HIGH + def _getName(self): """ Returns the show name if there is a show object created, if not returns @@ -319,12 +319,12 @@ class QueueItemAdd(ShowQueueItem): self.show.release_groups.set_white_keywords(self.whitelist) # be smartish about this - if self.show.genre and "talk show" in self.show.genre.lower(): - self.show.air_by_date = 1 - if self.show.genre and "documentary" in self.show.genre.lower(): - self.show.air_by_date = 0 - if self.show.classification and "sports" in self.show.classification.lower(): - self.show.sports = 1 + #if self.show.genre and "talk show" in self.show.genre.lower(): + # self.show.air_by_date = 1 + #if self.show.genre and "documentary" in self.show.genre.lower(): + # self.show.air_by_date = 0 + #if self.show.classification and "sports" in self.show.classification.lower(): + # self.show.sports = 1 except sickbeard.indexer_exception, e: logger.log( @@ -438,7 +438,7 @@ class QueueItemRefresh(ShowQueueItem): ShowQueueItem.__init__(self, ShowQueueActions.REFRESH, show) # do refreshes first because they're quick - self.priority = generic_queue.QueuePriorities.HIGH + self.priority = generic_queue.QueuePriorities.NORMAL # force refresh certain items self.force = force diff --git a/sickbeard/subtitles.py b/sickbeard/subtitles.py index afb63ff7b9cefbea39bf87000f3aa06057dbf866..ebb0211533f6a84b95fdbaa3bcde81c670569d8f 100644 --- a/sickbeard/subtitles.py +++ b/sickbeard/subtitles.py @@ -20,6 +20,7 @@ import time import datetime import sickbeard from sickbeard.common import * +from sickbeard.exceptions import ex from sickbeard import notifiers from sickbeard import logger from sickbeard import encodingKludge as ek @@ -27,6 +28,7 @@ from sickbeard import db from sickbeard import history import subliminal import babelfish +import subprocess subliminal.cache_region.configure('dogpile.cache.memory') @@ -200,3 +202,32 @@ class SubtitlesFinder(): - the number of searches done so far (searchcount), represented by the index of the list """ return {'old': [0, 24], 'new': [0, 4, 8, 4, 16, 24, 24]} + + +def run_subs_extra_scripts(epObj, foundSubs): + + for curScriptName in sickbeard.SUBTITLES_EXTRA_SCRIPTS: + script_cmd = [piece for piece in re.split("( |\\\".*?\\\"|'.*?')", curScriptName) if piece.strip()] + script_cmd[0] = ek.ek(os.path.abspath, script_cmd[0]) + logger.log(u"Absolute path to script: " + script_cmd[0], logger.DEBUG) + + for video, subs in foundSubs.iteritems(): + subpaths = [] + for sub in subs: + subpath = subliminal.subtitle.get_subtitle_path(video.name, sub.language) + if sickbeard.SUBTITLES_DIR and ek.ek(os.path.exists, sickbeard.SUBTITLES_DIR): + subpath = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, ek.ek(os.path.basename, subpath)) + + inner_cmd = script_cmd + [video.name] + [subpath] + [sub.language.opensubtitles] + [epObj.show.name] + \ + [epObj.season] + [epObj.episode] + [epObj.name] + + # use subprocess to run the command and capture output + logger.log(u"Executing command: %s" % inner_cmd) + try: + p = subprocess.Popen(inner_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, cwd=sickbeard.PROG_DIR) + out, err = p.communicate() # @UnusedVariable + logger.log(u"Script result: %s" % out, logger.DEBUG) + + except Exception as e: + logger.log(u"Unable to run subs_extra_script: " + ex(e)) diff --git a/sickbeard/traktChecker.py b/sickbeard/traktChecker.py index 85f00b5bf55a5f603e50f332acd9905dffe68252..cfe667cfe67ab3105ff5c99ca0350029c3b9c822 100644 --- a/sickbeard/traktChecker.py +++ b/sickbeard/traktChecker.py @@ -46,7 +46,7 @@ def setEpisodeToWanted(show, s, e): if epObj.status != SKIPPED or epObj.airdate == datetime.date.fromordinal(1): return - logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to wanted") + logger.log(u"Setting episode %s S%02dE%02d to wanted" %(show.name, s, e)) # figure out what segment the episode is in and remember it so we can backlog it epObj.status = WANTED @@ -55,8 +55,7 @@ def setEpisodeToWanted(show, s, e): cur_backlog_queue_item = search_queue.BacklogQueueItem(show, [epObj]) sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item) - logger.log(u"Starting backlog for " + show.name + " season " + str( - s) + " episode " + str(e) + " because some eps were set to wanted") + logger.log(u"Starting backlog search for %s S%02dE%02d because some episodes were set to wanted" % (show.name, s, e)) class TraktChecker(): @@ -192,7 +191,8 @@ class TraktChecker(): trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._checkInList(trakt_id,str(cur_episode["showid"]),str(cur_episode["season"]),str(cur_episode["episode"]), List='Collection'): if cur_episode["location"] == '': - logger.log(u"Removing Episode: Indexer %s %s - %s - S%sE%s from Collection" % (trakt_id,str(cur_episode["showid"]), cur_episode["show_name"],str(cur_episode["season"]),str(cur_episode["episode"])), logger.DEBUG) + logger.log(u"Removing Episode %s S%02dE%02d from collection" % + (cur_episode["show_name"],cur_episode["season"],cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"],cur_episode["indexer"],cur_episode["show_name"],cur_episode["startyear"],cur_episode["season"], cur_episode["episode"])) if len(trakt_data): @@ -214,7 +214,8 @@ class TraktChecker(): for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._checkInList(trakt_id,str(cur_episode["showid"]),str(cur_episode["season"]),str(cur_episode["episode"]), List='Collection'): - logger.log(u"Adding Episode: Indexer %s %s - %s - S%sE%s to Collection" % (trakt_id,str(cur_episode["showid"]), cur_episode["show_name"],str(cur_episode["season"]),str(cur_episode["episode"])), logger.DEBUG) + logger.log(u"Adding Episode %s S%02dE%02d to collection" % + (cur_episode["show_name"],cur_episode["season"],cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"],cur_episode["indexer"],cur_episode["show_name"],cur_episode["startyear"],cur_episode["season"], cur_episode["episode"])) if len(trakt_data): @@ -252,7 +253,8 @@ class TraktChecker(): trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._checkInList(trakt_id,str(cur_episode["showid"]),str(cur_episode["season"]),str(cur_episode["episode"])): if cur_episode["status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [UNKNOWN] + [WANTED]: - logger.log(u"Removing Episode: Indexer %s %s - %s - S%sE%s from Watchlist" % (trakt_id,str(cur_episode["showid"]), cur_episode["show_name"],str(cur_episode["season"]),str(cur_episode["episode"])), logger.DEBUG) + logger.log(u"Removing Episode %s S%02dE%02d from watchlist" % + (cur_episode["show_name"],cur_episode["season"],cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"],cur_episode["indexer"],cur_episode["show_name"],cur_episode["startyear"],cur_episode["season"], cur_episode["episode"])) if len(trakt_data): @@ -274,7 +276,8 @@ class TraktChecker(): for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._checkInList(trakt_id,str(cur_episode["showid"]),str(cur_episode["season"]),str(cur_episode["episode"])): - logger.log(u"Adding Episode: Indexer %s %s - %s - S%sE%s to Watchlist" % (trakt_id,str(cur_episode["showid"]), cur_episode["show_name"],str(cur_episode["season"]),str(cur_episode["episode"])), logger.DEBUG) + logger.log(u"Adding Episode %s S%02dE%02d to watchlist" % + (cur_episode["show_name"],cur_episode["season"],cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"],cur_episode["indexer"],cur_episode["show_name"],cur_episode["startyear"],cur_episode["season"], cur_episode["episode"])) if len(trakt_data): @@ -786,7 +789,7 @@ class TraktRolling(): if epObj.status != SKIPPED: return - logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to " + statusStrings[sickbeard.EP_DEFAULT_DELETED_STATUS]) + logger.log(u"Setting episode %s S%02dE%02d to %s " % (show.name, s, e, statusStrings[sickbeard.EP_DEFAULT_DELETED_STATUS] )) epObj.status = sickbeard.EP_DEFAULT_DELETED_STATUS epObj.saveToDB() diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 260a06b1ca5ef74cebc9ee755b321990da88ce4c..7f48acf1a1226288e4c43af989bf89379482eff2 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -263,8 +263,7 @@ class TVShow(object): episode = int(sqlResults[0]["episode"]) season = int(sqlResults[0]["season"]) logger.log( - "Found episode by absolute_number:" + str(absolute_number) + " which is " + str(season) + "x" + str( - episode), logger.DEBUG) + "Found episode by absolute_number %s which is S%02dE%02d" % (absolute_number, season, episode), logger.DEBUG) elif len(sqlResults) > 1: logger.log("Multiple entries for absolute number: " + str( absolute_number) + " in show: " + self.name + " found ", logger.ERROR) @@ -282,8 +281,7 @@ class TVShow(object): if noCreate: return None - logger.log(str(self.indexerid) + u": An object for episode " + str(season) + "x" + str( - episode) + " didn't exist in the cache, trying to create it", logger.DEBUG) + logger.log(str(self.indexerid) + u": An object for episode S%02dE%02d didn't exist in the cache, trying to create it" % (season, episode), logger.DEBUG) if file: ep = TVEpisode(self, season, episode, file) @@ -376,8 +374,7 @@ class TVShow(object): sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND location != ''", [self.indexerid]) for epResult in sqlResults: - logger.log(str(self.indexerid) + u": Retrieving/creating episode " + str(epResult["season"]) + "x" + str( - epResult["episode"]), logger.DEBUG) + logger.log(str(self.indexerid) + u": Retrieving/creating episode S%02dE%02d" % (epResult["season"], epResult["episode"]), logger.DEBUG) curEp = self.getEpisode(epResult["season"], epResult["episode"]) if not curEp: continue @@ -514,7 +511,7 @@ class TVShow(object): if not curSeason in scannedEps: scannedEps[curSeason] = {} - logger.log(u"Loading episode " + str(curSeason) + "x" + str(curEpisode) + " from the DB", logger.DEBUG) + logger.log(u"Loading episode S%02dE%02d from the DB" % (curSeason, curEpisode), logger.DEBUG) try: curEp = self.getEpisode(curSeason, curEpisode) @@ -574,9 +571,7 @@ class TVShow(object): if not ep: raise exceptions.EpisodeNotFoundException except exceptions.EpisodeNotFoundException: - logger.log( - str(self.indexerid) + ": " + sickbeard.indexerApi(self.indexer).name + " object for " + str( - season) + "x" + str(episode) + " is incomplete, skipping this episode") + logger.log("%s: %s object for S%02dE%02d is incomplete, skipping this episode" % (self.indexerid, sickbeard.indexerApi(self.indexer).name, season, episode)) continue else: try: @@ -586,8 +581,7 @@ class TVShow(object): continue with ep.lock: - logger.log(str(self.indexerid) + u": Loading info from " + sickbeard.indexerApi( - self.indexer).name + " for episode " + str(season) + "x" + str(episode), logger.DEBUG) + logger.log("%s: Loading info from %s for episode S%02dE%02d" % (self.indexerid, sickbeard.indexerApi(self.indexer).name, season, episode),logger.DEBUG) ep.loadFromIndexer(season, episode, tvapi=t) sql_l.append(ep.get_sql()) @@ -645,7 +639,7 @@ class TVShow(object): if not len(parse_result.episode_numbers): logger.log("parse_result: " + str(parse_result)) - logger.log(u"No episode number found in " + file + ", ignoring it", logger.ERROR) + logger.log(u"No episode number found in " + file + ", ignoring it", logger.WARNING) return None # for now lets assume that any episode in the show dir belongs to that show @@ -658,9 +652,7 @@ class TVShow(object): episode = int(curEpNum) - logger.log( - str(self.indexerid) + ": " + file + " parsed to " + self.name + " " + str(season) + "x" + str(episode), - logger.DEBUG) + logger.log("%s: %s parsed to %s S%02dE%02d" % (self.indexerid, file, self.name, season, episode), logger.DEBUG) checkQualityAgain = False same_file = False @@ -987,8 +979,7 @@ class TVShow(object): logger.DEBUG) self.nextaired = "" else: - logger.log(str(self.indexerid) + u": Found episode " + str(sqlResults[0]["season"]) + "x" + str( - sqlResults[0]["episode"]), logger.DEBUG) + logger.log(u"%s: Found episode S%02dE%02d" % (self.indexerid, sqlResults[0]["season"], sqlResults[0]["episode"] ) , logger.DEBUG) self.nextaired = sqlResults[0]['airdate'] return self.nextaired @@ -1099,9 +1090,8 @@ class TVShow(object): with curEp.lock: # if it used to have a file associated with it and it doesn't anymore then set it to sickbeard.EP_DEFAULT_DELETED_STATUS if curEp.location and curEp.status in Quality.DOWNLOADED: - logger.log(str(self.indexerid) + u": Location for " + str(season) + "x" + str( - episode) + " doesn't exist, removing it and changing our status to " + statusStrings[sickbeard.EP_DEFAULT_DELETED_STATUS], - logger.DEBUG) + logger.log(u"%s: Location for S%02dE%02d doesn't exist, removing it and changing our status to %s" % + (self.indexerid, season, episode, statusStrings[sickbeard.EP_DEFAULT_DELETED_STATUS]) ,logger.DEBUG) curEp.status = sickbeard.EP_DEFAULT_DELETED_STATUS curEp.subtitles = list() curEp.subtitles_searchcount = 0 @@ -1233,8 +1223,7 @@ class TVShow(object): def wantEpisode(self, season, episode, quality, manualSearch=False, downCurQuality=False): - logger.log(u"Checking if found episode " + "S" + str(season).zfill(2) + "E" + str(episode).zfill(2) + " is wanted at quality " + - Quality.qualityStrings[quality], logger.DEBUG) + logger.log(u"Checking if found episode %s S%02dE%02d is wanted at quality %s" % (self.name, season, episode, Quality.qualityStrings[quality]) , logger.DEBUG) # if the quality isn't one we want under any circumstances then just say no anyQualities, bestQualities = Quality.splitQuality(self.quality) @@ -1480,6 +1469,17 @@ class TVEpisode(object): subliminal.save_subtitles(foundSubs, directory=subs_new_path, single=not sickbeard.SUBTITLES_MULTI) + for video, subs in foundSubs.iteritems(): + for sub in subs: + subpath = subliminal.subtitle.get_subtitle_path(video.name, sub.language) + if sickbeard.SUBTITLES_DIR and ek.ek(os.path.exists, sickbeard.SUBTITLES_DIR): + subpath = ek.ek(os.path.join, sickbeard.SUBTITLES_DIR, ek.ek(os.path.basename, subpath)) + helpers.chmodAsParent(subpath) + helpers.fixSetGroupID(subpath) + + if not sickbeard.EMBEDDED_SUBTITLES_ALL and sickbeard.SUBTITLES_EXTRA_SCRIPTS and self.location.endswith(('mkv','mp4')): + subtitles.run_subs_extra_scripts(self, foundSubs) + except Exception as e: logger.log("Error occurred when downloading subtitles for: %s" % self.location) logger.log(traceback.format_exc(), logger.ERROR) @@ -1550,8 +1550,7 @@ class TVEpisode(object): try: self.loadFromNFO(self.location) except exceptions.NoNFOException: - logger.log(str(self.show.indexerid) + u": There was an error loading the NFO for episode " + str( - season) + "x" + str(episode), logger.ERROR) + logger.log(u"%s: There was an error loading the NFO for episode S%02dE%02d" % (self.show.indexerid, season, episode), logger.ERROR) pass # if we tried loading it from NFO and didn't find the NFO, try the Indexers @@ -1563,13 +1562,10 @@ class TVEpisode(object): # if we failed SQL *and* NFO, Indexers then fail if not result: - raise exceptions.EpisodeNotFoundException( - "Couldn't find episode " + str(season) + "x" + str(episode)) + raise exceptions.EpisodeNotFoundException("Couldn't find episode S%02dE%02d" % (season, episode)) def loadFromDB(self, season, episode): - logger.log( - str(self.show.indexerid) + u": Loading episode details from DB for episode " + str(season) + "x" + str( - episode), logger.DEBUG) + logger.log(u"%s: Loading episode details from DB for episode %s S%02dE%02d" % (self.show.indexerid, self.show.name, season, episode), logger.DEBUG) myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", @@ -1578,8 +1574,7 @@ class TVEpisode(object): if len(sqlResults) > 1: raise exceptions.MultipleDBEpisodesException("Your DB has two records for the same show somehow.") elif len(sqlResults) == 0: - logger.log(str(self.show.indexerid) + u": Episode " + str(self.season) + "x" + str( - self.episode) + " not found in the database", logger.DEBUG) + logger.log(u"%s: Episode S%02dE%02d not found in the database" % (self.show.indexerid, self.season, self.episode), logger.DEBUG) return False else: # NAMEIT logger.log(u"AAAAA from" + str(self.season)+"x"+str(self.episode) + " -" + self.name + " to " + str(sqlResults[0]["name"])) @@ -1664,8 +1659,7 @@ class TVEpisode(object): if episode is None: episode = self.episode - logger.log(str(self.show.indexerid) + u": Loading episode details from " + sickbeard.indexerApi( - self.show.indexer).name + " for episode " + str(season) + "x" + str(episode), logger.DEBUG) + logger.log(u"%s: Loading episode details from %s for episode S%02dE%02d" % (sickbeard.indexerApi(self.show.indexer).name, season, episode) , logger.DEBUG) indexer_lang = self.show.lang @@ -1711,21 +1705,16 @@ class TVEpisode(object): return if getattr(myEp, 'episodename', None) is None: - logger.log(u"This episode (" + self.show.name + " - " + str(season) + "x" + str( - episode) + ") has no name on " + sickbeard.indexerApi(self.indexer).name + "") + logger.log(u"This episode %s - S%02dE%02d has no name on %s" %(self.show.name, season, episode, sickbeard.indexerApi(self.indexer).name)) # if I'm incomplete on TVDB but I once was complete then just delete myself from the DB for now if self.indexerid != -1: self.deleteEpisode() return False if getattr(myEp, 'absolute_number', None) is None: - logger.log(u"This episode (" + self.show.name + " - " + str(season) + "x" + str( - episode) + ") has no absolute number on " + sickbeard.indexerApi( - self.indexer).name, logger.DEBUG) + logger.log(u"This episode %s - S%02dE%02d has no absolute number on %s" %(self.show.name, season, episode, sickbeard.indexerApi(self.indexer).name), logger.DEBUG) else: - logger.log( - str(self.show.indexerid) + ": The absolute_number for " + str(season) + "x" + str(episode) + " is : " + - str(myEp["absolute_number"]), logger.DEBUG) + logger.log(u"%s: The absolute_number for S%02dE%02d is: %s " % (self.show.indexerid, season, episode, myEp["absolute_number"]), logger.DEBUG) self.absolute_number = int(myEp["absolute_number"]) self.name = getattr(myEp, 'episodename', "") @@ -1756,9 +1745,7 @@ class TVEpisode(object): try: self.airdate = datetime.date(rawAirdate[0], rawAirdate[1], rawAirdate[2]) except (ValueError, IndexError): - logger.log(u"Malformed air date of " + str(firstaired) + " retrieved from " + sickbeard.indexerApi( - self.indexer).name + " for (" + self.show.name + " - " + str(season) + "x" + str(episode) + ")", - logger.WARNING) + logger.log(u"Malformed air date of %s retrieved from %s for (%s - S%02dE%02d)" % (firstaired, sickbeard.indexerApi(self.indexer).name, self.show.name, season, episode),logger.WARNING) # if I'm incomplete on the indexer but I once was complete then just delete myself from the DB for now if self.indexerid != -1: self.deleteEpisode() @@ -1775,8 +1762,7 @@ class TVEpisode(object): # don't update show status if show dir is missing, unless it's missing on purpose if not ek.ek(os.path.isdir, self.show._location) and not sickbeard.CREATE_MISSING_SHOW_DIRS and not sickbeard.ADD_SHOWS_WO_DIR: - logger.log( - u"The show dir " + str(self.show._location) + " is missing, not bothering to change the episode statuses since it'd probably be invalid") + logger.log(u"The show dir %s is missing, not bothering to change the episode statuses since it'd probably be invalid" % self.show._location ) return if self.location: @@ -1850,10 +1836,7 @@ class TVEpisode(object): if epDetails.findtext('season') is None or int(epDetails.findtext('season')) != self.season or \ epDetails.findtext('episode') is None or int( epDetails.findtext('episode')) != self.episode: - logger.log(str( - self.show.indexerid) + u": NFO has an <episodedetails> block for a different episode - wanted " + str( - self.season) + "x" + str(self.episode) + " but got " + str( - epDetails.findtext('season')) + "x" + str(epDetails.findtext('episode')), logger.DEBUG) + logger.log(u": NFO has an <episodedetails> block for a different episode - wanted S%02dE%02d but got S%02dE%02d" % (self.show.indexerid, self.season, self.episode, epDetails.findtext('season'), epDetails.findtext('episode') ), logger.DEBUG) continue if epDetails.findtext('title') is None or epDetails.findtext('aired') is None: @@ -1899,8 +1882,7 @@ class TVEpisode(object): def __str__(self): toReturn = "" - toReturn += str(self.show.name) + " - " + str(self.season) + "x" + str(self.episode) + " - " + str( - self.name) + "\n" + toReturn += "%s - S%02dE%02d - %s " % (self.show.name, self.season, self.episode, self.name ) + "\n" toReturn += "location: " + str(self.location) + "\n" toReturn += "description: " + str(self.description) + "\n" toReturn += "subtitles: " + str(",".join(self.subtitles)) + "\n" @@ -1944,8 +1926,7 @@ class TVEpisode(object): def deleteEpisode(self): - logger.log(u"Deleting " + self.show.name + " " + str(self.season) + "x" + str(self.episode) + " from the DB", - logger.DEBUG) + logger.log(u"Deleting %s S%02dE%02dfrom the DB" % (self.show.name, self.season, self.episode), logger.DEBUG) # remove myself from the show dictionary if self.show.getEpisode(self.season, self.episode, noCreate=True) == self: diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 51fb8938a2d3744e5ac5f8cf122c1b8b3aa629f7..d7c90d58cad7049504230deacc58b77ce0d4d1b4 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -175,7 +175,7 @@ class ApiHandler(RequestHandler): cmd, cmdIndex = cmd.split("_") # this gives us the clear cmd and the index logger.log(u"API :: " + cmd + ": curKwargs " + str(curKwargs), logger.DEBUG) - if not (multiCmds and cmd in ('show.getposter', 'show.getbanner', 'show.getnetworklogo')): # skip these cmd while chaining + if not (multiCmds and cmd in ('show.getbanner', 'show.getfanart', 'show.getnetworklogo', 'show.getposter')): # skip these cmd while chaining try: if cmd in _functionMaper: # map function @@ -1100,11 +1100,10 @@ class CMD_SubtitleSearch(ApiCall): return _responds(RESULT_FAILURE, msg='Unable to find subtitles') # return the correct json value - if previous_subtitles != epObj.subtitles: - status = 'New subtitles downloaded: %s' % ' '.join([ - "<img src='" + sickbeard.WEB_ROOT + "/images/flags/" + babelfish.language.Language( - x).alpha2 + ".png' alt='" + babelfish.language.Language(x).name + "'/>" for x in - sorted(list(set(epObj.subtitles).difference(previous_subtitles)))]) + newSubtitles = frozenset(ep_obj.subtitles).difference(previous_subtitles) + if newSubtitles: + newLangs = [subtitles.fromietf(newSub) for newSub in newSubtitles] + status = 'New subtitles downloaded: %s' % ', '.join([newLang.name for newLang in newLangs]) response = _responds(RESULT_SUCCESS, msg='New subtitles found') else: status = 'No subtitles downloaded' @@ -2447,6 +2446,7 @@ class CMD_ShowGetBanner(ApiCall): """ get the banner for a show in sickrage """ return {'outputType': 'image', 'image': self.rh.showPoster(self.indexerid, 'banner')} + class CMD_ShowGetNetworkLogo(ApiCall): _help = { "desc": "Get the network logo stored for a show in SickRage", @@ -2481,6 +2481,34 @@ class CMD_ShowGetNetworkLogo(ApiCall): 'image': self.rh.showNetworkLogo(self.indexerid) } + +class CMD_ShowGetFanArt(ApiCall): + _help = { + "desc": "Get the fan art stored for a show in SickRage", + "requiredParameters": { + "indexerid": {"desc": "Unique id of a show"} + }, + "optionalParameters": { + "tvdbid": {"desc": "thetvdb.com unique id of a show"}, + "tvrageid": {"desc": "tvrage.com unique id of a show"}, + }, + } + + def __init__(self, args, kwargs): + # required + self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", []) + # optional + # super, missing, help + ApiCall.__init__(self, args, kwargs) + + def run(self): + """ Get the fan art for a show in SickRage """ + return { + 'outputType': 'image', + 'image': self.rh.showPoster(self.indexerid, 'fanart') + } + + class CMD_ShowPause(ApiCall): _help = {"desc": "set a show's paused state in sickrage", "requiredParameters": { @@ -3012,6 +3040,7 @@ _functionMaper = {"help": CMD_Help, "show.getposter": CMD_ShowGetPoster, "show.getbanner": CMD_ShowGetBanner, "show.getnetworklogo": CMD_ShowGetNetworkLogo, + "show.getfanart": CMD_ShowGetFanArt, "show.pause": CMD_ShowPause, "show.refresh": CMD_ShowRefresh, "show.seasonlist": CMD_ShowSeasonList, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 45060b32bb854c5d73239b752da94ecf2fb0bf9a..1ac8621b1435b260a2bac5e1f60ae3c0ea92ac23 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -2157,6 +2157,20 @@ class Home(WebRoot): return json.dumps({'result': 'failure'}) +@route('/IRC(/?.*)') +class HomeIRC(Home): + def __init__(self, *args, **kwargs): + super(HomeIRC, self).__init__(*args, **kwargs) + + def index(self): + + t = PageTemplate(rh=self, file="IRC.tmpl") + t.submenu = self.HomeMenu() + t.title = "IRC" + t.header = "IRC" + t.topmenu = "IRC" + return t.respond() + @route('/news(/?.*)') class HomeNews(Home): def __init__(self, *args, **kwargs): @@ -4928,7 +4942,7 @@ class ConfigSubtitles(Config): def saveSubtitles(self, use_subtitles=None, subtitles_plugins=None, subtitles_languages=None, subtitles_dir=None, service_order=None, subtitles_history=None, subtitles_finder_frequency=None, - subtitles_multi=None, embedded_subtitles_all=None): + subtitles_multi=None, embedded_subtitles_all=None, subtitles_extra_scripts=None): results = [] @@ -4940,6 +4954,7 @@ class ConfigSubtitles(Config): sickbeard.SUBTITLES_HISTORY = config.checkbox_to_value(subtitles_history) sickbeard.EMBEDDED_SUBTITLES_ALL = config.checkbox_to_value(embedded_subtitles_all) sickbeard.SUBTITLES_MULTI = config.checkbox_to_value(subtitles_multi) + sickbeard.SUBTITLES_EXTRA_SCRIPTS = [x.strip() for x in subtitles_extra_scripts.split('|') if x.strip()] # Subtitles services services_str_list = service_order.split()