def test_logSnatch(self): myDB = db.DBConnection("../sickbeard.db") #res = myDB.select("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;") #for r in res: #print r["name"] #print "tables-----------------------" searchResult=SearchResults([Episode(12345,2,4),Episode(54321,1,3)]) history.logSnatch(searchResult) #check if elements added res=myDB.select("SELECT COUNT(*) FROM history WHERE (action=? AND date=? AND showid=? AND season=? AND episode=? AND quality=? AND resource=? AND provider=?)", [Quality.compositeStatus(SNATCHED, 4), datetime.datetime.today().strftime(dateFormat), 12345, 2, 4, 4, "searchName", "unknown"]) self.assertEqual(len(res),1) res=myDB.select("SELECT COUNT(*) FROM history WHERE (action=? AND date=? AND showid=? AND season=? AND episode=? AND quality=? AND resource=? AND provider=?)", [Quality.compositeStatus(SNATCHED, 4), datetime.datetime.today().strftime(dateFormat), 54321, 1, 3, 4, "searchName", "unknown"]) self.assertEqual(len(res),1) #delete just-added elements myDB.action("DELETE FROM history WHERE (action=? AND date=? AND showid=? AND season=? AND episode=? AND quality=? AND resource=? AND provider=?)", [Quality.compositeStatus(SNATCHED, 4), datetime.datetime.today().strftime(dateFormat), 12345, 2, 4, 4, "searchName", "unknown"]) myDB.action("DELETE FROM history WHERE (action=? AND date=? AND showid=? AND season=? AND episode=? AND quality=? AND resource=? AND provider=?)", [Quality.compositeStatus(SNATCHED, 4), datetime.datetime.today().strftime(dateFormat), 54321, 1, 3, 4, "searchName", "unknown"])
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): # make a fake episode object ep = TVEpisode(2, 3, 3, "Ep Name") # pylint: disable=protected-access ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) ep._airdate = datetime.date(2011, 3, 9) if abd: ep._release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP' ep.show.air_by_date = 1 elif sports: ep._release_name = 'Show.Name.2011.03.09.HDTV.XviD-RLSGROUP' ep.show.sports = 1 else: if anime_type != 3: ep.show.anime = 1 ep._release_name = 'Show.Name.003.HDTV.XviD-RLSGROUP' else: ep._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' if multi is not None: ep._name = "Ep Name (1)" if anime_type != 3: ep.show.anime = 1 ep._release_name = 'Show.Name.003-004.HDTV.XviD-RLSGROUP' secondEp = TVEpisode(2, 4, 4, "Ep Name (2)") secondEp._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) secondEp._release_name = ep._release_name ep.relatedEps.append(secondEp) else: ep._release_name = 'Show.Name.S02E03E04E05.HDTV.XviD-RLSGROUP' secondEp = TVEpisode(2, 4, 4, "Ep Name (2)") secondEp._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) secondEp._release_name = ep._release_name thirdEp = TVEpisode(2, 5, 5, "Ep Name (3)") thirdEp._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) thirdEp._release_name = ep._release_name ep.relatedEps.append(secondEp) ep.relatedEps.append(thirdEp) return ep
def logSnatch(searchResult): """ Log history of snatch :param searchResult: search result object """ for curEpObj in searchResult.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = searchResult.quality version = searchResult.version providerClass = searchResult.provider if providerClass != None: provider = providerClass.name else: provider = "unknown" action = Quality.compositeStatus(SNATCHED, searchResult.quality) resource = searchResult.name _logHistoryItem(action, showid, season, episode, quality, resource, provider, version)
def logSubtitle(showid, season, episode, status, subtitleResult): resource = subtitleResult.path provider = subtitleResult.service status, quality = Quality.splitCompositeStatus(status) action = Quality.compositeStatus(SUBTITLED, quality) _logHistoryItem(action, showid, season, episode, quality, resource, provider)
def logSnatch(searchResult): """ Log history of snatch :param searchResult: search result object """ for curEpObj in searchResult.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = searchResult.quality version = searchResult.version providerClass = searchResult.provider if providerClass is not None: provider = providerClass.name else: provider = "unknown" action = Quality.compositeStatus(SNATCHED, searchResult.quality) resource = searchResult.name _logHistoryItem(action, showid, season, episode, quality, resource, provider, version)
def history_snatched_proper_fix(): my_db = db.DBConnection() if not my_db.has_flag('history_snatch_proper'): logger.log('Updating history items with status Snatched Proper in a background process...') sql_result = my_db.select('SELECT rowid, resource, quality, showid' ' FROM history' ' WHERE action LIKE "%%%02d"' % SNATCHED + ' AND (UPPER(resource) LIKE "%PROPER%"' ' OR UPPER(resource) LIKE "%REPACK%"' ' OR UPPER(resource) LIKE "%REAL%")') if sql_result: cl = [] for r in sql_result: show_obj = None try: show_obj = helpers.findCertainShow(sickbeard.showList, int(r['showid'])) except (StandardError, Exception): pass np = NameParser(False, showObj=show_obj, testing=True) try: pr = np.parse(r['resource']) except (StandardError, Exception): continue if 0 < Quality.get_proper_level(pr.extra_info_no_name(), pr.version, pr.is_anime): cl.append(['UPDATE history SET action = ? WHERE rowid = ?', [Quality.compositeStatus(SNATCHED_PROPER, int(r['quality'])), r['rowid']]]) if cl: my_db.mass_action(cl) logger.log('Completed the history table update with status Snatched Proper.') my_db.add_flag('history_snatch_proper')
def logFailed(epObj, release, provider=None): showid = int(epObj.show.indexerid) season = int(epObj.season) epNum = int(epObj.episode) status, quality = Quality.splitCompositeStatus(epObj.status) action = Quality.compositeStatus(FAILED, quality) _logHistoryItem(action, showid, season, epNum, quality, release, provider)
def logFailed(tvdbid, season, episode, status, release, provider=None): showid = int(tvdbid) season = int(season) epNum = int(episode) status, quality = Quality.splitCompositeStatus(status) action = Quality.compositeStatus(FAILED, quality) _logHistoryItem(action, showid, season, epNum, quality, release, provider)
def set_episode_failed(ep_obj): try: with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except EpisodeNotFoundException as e: logger.log('Unable to get episode, please set its status manually: %s' % ex(e), logger.WARNING)
def markFailed(epObj): log_str = u"" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException, e: logger.log(u"Unable to get episode, please set its status manually: " + ex(e), logger.WARNING)
def set_episode_failed(ep_obj): try: with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except EpisodeNotFoundException as e: logger.log( 'Unable to get episode, please set its status manually: %s' % ex(e), logger.WARNING)
def __init__(self, season, episode, absolute_number, name): # pylint: disable=super-init-not-called super(TVEpisode, self).__init__(None, season, episode) self.related_episodes = [] self.name = name self.absolute_number = absolute_number self.scene_season = season self.scene_episode = episode self.scene_absolute_number = absolute_number self.airdate = datetime.date(2010, 3, 9) self.status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) self.release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' self.is_proper = True self.show = TVShow()
def markFailed(show_obj, season, episode=None): log_str = u"" if episode: try: ep_obj = show_obj.getEpisode(season, episode) with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except exceptions.EpisodeNotFoundException, e: log_str += _log_helper(u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
def __init__(self, season, episode, absolute_number, name): self.relatedEps = [] self._name = name self._season = season self._episode = episode self._absolute_number = absolute_number self.scene_season = season self.scene_episode = episode self.scene_absolute_number = absolute_number self._airdate = datetime.date(2010, 3, 9) self.show = TVShow() self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) self._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' self._is_proper = True
def __init__(self, season, episode, absolute_number, name): # pylint: disable=super-init-not-called self.relatedEps = [] self._name = name self._season = season self._episode = episode self._absolute_number = absolute_number self.scene_season = season self.scene_episode = episode self.scene_absolute_number = absolute_number self._airdate = datetime.date(2010, 3, 9) self.show = TVShow() self._status = Quality.compositeStatus(common.DOWNLOADED, common.Quality.SDTV) self._release_name = 'Show.Name.S02E03.HDTV.XviD-RLSGROUP' self._is_proper = True
def logFailed(epObj, release, provider=None): """ Log a failed download :param epObj: Episode object :param release: Release group :param provider: Provider used for snatch """ showid = int(epObj.show.indexerid) season = int(epObj.season) epNum = int(epObj.episode) status, quality = Quality.splitCompositeStatus(epObj.status) action = Quality.compositeStatus(FAILED, quality) _logHistoryItem(action, showid, season, epNum, quality, release, provider)
def test_should_delete_episode(self): test_cases = [ ((SNATCHED, Quality.HDTV), False), ((SNATCHED_PROPER, Quality.HDTV), False), ((SNATCHED_BEST, Quality.HDTV), False), ((DOWNLOADED, Quality.HDTV), False), ((ARCHIVED, Quality.HDTV), False), ((ARCHIVED, Quality.NONE), False), ((SKIPPED, Quality.NONE), True), ((IGNORED, Quality.NONE), False), ((UNAIRED, Quality.NONE), True), ((UNKNOWN, Quality.NONE), True), ((WANTED, Quality.NONE), True), ] for c, b in test_cases: self.assertEqual(helpers.should_delete_episode(Quality.compositeStatus(*c)), b)
def markFailed(show_obj, season, episode=None): log_str = u"" if episode: try: ep_obj = show_obj.getEpisode(season, episode) with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except exceptions.EpisodeNotFoundException, e: log_str += _log_helper( u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
def test_should_delete_episode(self): test_cases = [ ((SNATCHED, Quality.HDTV), False), ((SNATCHED_PROPER, Quality.HDTV), False), ((SNATCHED_BEST, Quality.HDTV), False), ((DOWNLOADED, Quality.HDTV), False), ((ARCHIVED, Quality.HDTV), False), ((ARCHIVED, Quality.NONE), False), ((SKIPPED, Quality.NONE), True), ((IGNORED, Quality.NONE), False), ((UNAIRED, Quality.NONE), True), ((UNKNOWN, Quality.NONE), True), ((WANTED, Quality.NONE), True), ] for c, b in test_cases: self.assertEqual( helpers.should_delete_episode(Quality.compositeStatus(*c)), b)
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = u"" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException, e: logger.log(u"Unable to get episode, please set its status manually: " + ex(e), logger.WARNING)
def logSubtitle(showid, season, episode, status, subtitleResult): """ Log download of subtitle :param showid: Showid of download :param season: Show season :param episode: Show episode :param status: Status of download :param subtitleResult: Result object """ resource = subtitleResult.language.opensubtitles provider = subtitleResult.provider_name status, quality = Quality.splitCompositeStatus(status) action = Quality.compositeStatus(SUBTITLED, quality) _logHistoryItem(action, showid, season, episode, quality, resource, provider)
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = "" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException as e: logging.warning("Unable to get episode, please set its status manually: {}".format(ex(e))) return log_str
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = u"" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException, e: logger.log( u"Unable to get episode, please set its status manually: " + ex(e), logger.WARNING)
def history_snatched_proper_fix(): my_db = db.DBConnection() if not my_db.has_flag('history_snatch_proper'): logger.log( 'Updating history items with status Snatched Proper in a background process...' ) sql_result = my_db.select('SELECT rowid, resource, quality, showid' ' FROM history' ' WHERE action LIKE "%%%02d"' % SNATCHED + ' AND (UPPER(resource) LIKE "%PROPER%"' ' OR UPPER(resource) LIKE "%REPACK%"' ' OR UPPER(resource) LIKE "%REAL%")') if sql_result: cl = [] for r in sql_result: show_obj = None try: show_obj = helpers.findCertainShow(sickbeard.showList, int(r['showid'])) except (StandardError, Exception): pass np = NameParser(False, showObj=show_obj, testing=True) try: pr = np.parse(r['resource']) except (StandardError, Exception): continue if 0 < Quality.get_proper_level(pr.extra_info_no_name(), pr.version, pr.is_anime): cl.append([ 'UPDATE history SET action = ? WHERE rowid = ?', [ Quality.compositeStatus(SNATCHED_PROPER, int(r['quality'])), r['rowid'] ] ]) if cl: my_db.mass_action(cl) logger.log( 'Completed the history table update with status Snatched Proper.' ) my_db.add_flag('history_snatch_proper')
def logSnatch(searchResult): for curEpObj in searchResult.episodes: showid = int(curEpObj.show.tvdbid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = searchResult.quality providerClass = searchResult.provider if providerClass != None: provider = providerClass.name else: provider = "unknown" action = Quality.compositeStatus(SNATCHED, searchResult.quality) resource = searchResult.name _logHistoryItem(action, showid, season, episode, quality, resource, provider)
def logSnatch(searchResult): for curEpObj in searchResult.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = searchResult.quality providerClass = searchResult.provider if providerClass != None: provider = providerClass.name else: provider = "unknown" action = Quality.compositeStatus(SNATCHED, searchResult.quality) resource = searchResult.name _logHistoryItem(action, showid, season, episode, quality, resource, provider)
def log_snatch(search_result): for curEpObj in search_result.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = search_result.quality version = search_result.version is_proper = 0 < search_result.properlevel provider_class = search_result.provider if None is not provider_class: provider = provider_class.name else: provider = 'unknown' action = Quality.compositeStatus((SNATCHED, SNATCHED_PROPER)[is_proper], search_result.quality) resource = search_result.name _log_history_item(action, showid, season, episode, quality, resource, provider, version)
def markFailed(epObj): """ Mark an episode as failed :param epObj: Episode object to mark as failed :return: empty string """ log_str = "" try: with epObj.lock: quality = Quality.splitCompositeStatus(epObj.status)[1] epObj.status = Quality.compositeStatus(FAILED, quality) epObj.saveToDB() except EpisodeNotFoundException as e: logging.warning( "Unable to get episode, please set its status manually: {}".format( ex(e))) return log_str
def log_snatch(search_result): for curEpObj in search_result.episodes: showid = int(curEpObj.show.indexerid) season = int(curEpObj.season) episode = int(curEpObj.episode) quality = search_result.quality version = search_result.version is_proper = 0 < search_result.properlevel provider_class = search_result.provider if None is not provider_class: provider = provider_class.name else: provider = 'unknown' action = Quality.compositeStatus( (SNATCHED, SNATCHED_PROPER)[is_proper], search_result.quality) resource = search_result.name _log_history_item(action, showid, season, episode, quality, resource, provider, version)
def test_getWanted(self): for ep_base, w in enumerate(wanted_tests): show_obj = TVShow(w['show']['indexer'], w['show']['indexerid'], 'en') show_obj.name = 'show name' show_obj.tvrname = 'show name' show_obj.quality = w['show']['quality'] show_obj.network = 'cbs' show_obj.genre = 'crime' show_obj.runtime = 40 show_obj.status = '5' show_obj.airs = 'monday' show_obj.startyear = 1987 show_obj.save_to_db() sickbeard.showList = [show_obj] sickbeard.showDict[show_obj.sid_int] = show_obj cl = [] ep_id = ep_base * 10000 for ep in w['episodes']: ep_id += 1 if ep['season'] not in show_obj.sxe_ep_obj: show_obj.sxe_ep_obj[ep['season']] = {} show_obj.sxe_ep_obj[ep['season']][ep['episode']] = TVEpisode( show_obj, ep['season'], ep['episode']) episode = show_obj.sxe_ep_obj[ep['season']][ep['episode']] episode.status = Quality.compositeStatus( ep['status'], ep['quality']) episode.airdate = ep['airdate'] episode.name = 'nothing' episode.epid = ep_id episode.show_obj = show_obj episode.tvid = show_obj.tvid cl.append(episode.get_sql()) cur_db = db.DBConnection() if cl: cur_db.mass_action(cl) qi = QueueItemAdd(w['show']['indexer'], w['show']['indexerid'], '', None, Quality.NONE, None, None, None, False, False, False, None, None, w['start_wanted'], w['end_wanted'], None, None) qi.show_obj = show_obj # start tests tr = qi._get_wanted(cur_db, w['start_wanted'], False) self.assertEqual( tr, w['result']['start'].get('count'), msg='%s: start: got: %s, expected: %s' % (w['name'], tr, w['result']['start'].get('count'))) results = cur_db.select( 'SELECT status, season, episode FROM tv_episodes WHERE indexer = ? AND showid = ?' ' ORDER BY season, episode', [show_obj.tvid, show_obj.prodid]) for r in results: expected = w['result']['start'].get('episodes').get( r['season'], {}).get(r['episode'], None) self.assertEqual( r['status'], expected, msg='%s: start %sx%s: got: %s, expected: %s' % (w['name'], r['season'], r['episode'], statusStrings[r['status']], statusStrings[expected])) # end tests tr = qi._get_wanted(cur_db, w['end_wanted'], True) self.assertEqual(tr, w['result']['end'].get('count'), msg='%s: end: got: %s, expected: %s' % (w['name'], tr, w['result']['end'].get('count'))) results = cur_db.select( 'SELECT status, season, episode FROM tv_episodes WHERE indexer = ? AND showid = ?' ' ORDER BY season, episode', [show_obj.tvid, show_obj.prodid]) for r in results: expected = w['result']['end'].get('episodes').get( r['season'], {}).get(r['episode'], None) self.assertEqual( r['status'], expected, msg='%s: end %sx%s: got: %s, expected: %s' % (w['name'], r['season'], r['episode'], statusStrings[r['status']], statusStrings[expected]))
def snatchEpisode(result, endStatus=SNATCHED): # pylint: disable=too-many-branches, too-many-statements """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickbeard.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7): result.priority = 1 endStatus = SNATCHED_PROPER if re.search(r'\b(proper|repack|real)\b', result.name, re.I) else endStatus if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickbeard.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickbeard.NZB_METHOD == "sabnzbd": dlResult = sab.sendNZB(result) elif sickbeard.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = nzbget.sendNZB(result, is_proper) elif sickbeard.NZB_METHOD == "download_station": client = clients.getClientInstance(sickbeard.NZB_METHOD)( sickbeard.SYNOLOGY_DSM_HOST, sickbeard.SYNOLOGY_DSM_USERNAME, sickbeard.SYNOLOGY_DSM_PASSWORD) dlResult = client.sendNZB(result) else: logger.log("Unknown NZB action specified in config: " + sickbeard.NZB_METHOD, logger.ERROR) dlResult = False # Torrents can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickbeard.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith('magnet'): if result.provider.login(): result.content = result.provider.get_url(result.url, returns='content') if result.content or result.url.startswith('magnet'): client = clients.getClientInstance(sickbeard.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: logger.log("Torrent file content is empty", logger.WARNING) dlResult = False else: logger.log("Unknown result type, unable to download it ({0!r})".format(result.resultType), logger.ERROR) dlResult = False if not dlResult: return False if sickbeard.USE_FAILED_DOWNLOADS: failed_history.logSnatch(result) ui.notifications.message('Episode snatched', result.name) history.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: try: notifiers.notify_snatch("{0} from {1}".format(curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN'), result.provider.name)) # pylint: disable=protected-access except Exception: # Without this, when notification fail, it crashes the snatch thread and SR will # keep snatching until notification is sent logger.log("Failed to send snatch notification", logger.DEBUG) trakt_data.append((curEpObj.season, curEpObj.episode)) data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickbeard.USE_TRAKT and sickbeard.TRAKT_SYNC_WATCHLIST: logger.log("Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist", logger.DEBUG) if data: notifiers.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if sql_l: main_db_con = db.DBConnection() main_db_con.mass_action(sql_l) return True
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickbeard.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta( days=7): result.priority = 1 if re.search(r'(^|[\. _-])(proper|repack)([\. _-]|$)', result.name, re.I) is not None: endStatus = SNATCHED_PROPER if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickbeard.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickbeard.NZB_METHOD == "sabnzbd": dlResult = sab.sendNZB(result) elif sickbeard.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = nzbget.sendNZB(result, is_proper) else: logger.log( u"Unknown NZB action specified in config: " + sickbeard.NZB_METHOD, logger.ERROR) dlResult = False # Torrents can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickbeard.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith('magnet'): result.content = result.provider.get_url(result.url, need_bytes=True) if result.content or result.url.startswith('magnet'): client = clients.getClientIstance(sickbeard.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: logger.log(u"Torrent file content is empty", logger.WARNING) dlResult = False else: logger.log( u"Unknown result type, unable to download it (%r)" % result.resultType, logger.ERROR) dlResult = False if not dlResult: return False if sickbeard.USE_FAILED_DOWNLOADS: failed_history.logSnatch(result) ui.notifications.message('Episode snatched', result.name) history.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus( SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus( endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: try: notifiers.notify_snatch( curEpObj._format_pattern('%SN - %Sx%0E - %EN - %QN') + " from " + result.provider.name) except: # Without this, when notification fail, it crashes the snatch thread and SR will # keep snatching until notification is sent logger.log(u"Failed to send snatch notification", logger.DEBUG) trakt_data.append((curEpObj.season, curEpObj.episode)) data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickbeard.USE_TRAKT and sickbeard.TRAKT_SYNC_WATCHLIST: logger.log( u"Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist", logger.DEBUG) if data: notifiers.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if len(sql_l) > 0: myDB = db.DBConnection() myDB.mass_action(sql_l) return True
with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except exceptions.EpisodeNotFoundException, e: log_str += _log_helper( u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING) else: # Whole season for ep_obj in show_obj.getAllEpisodes(season): with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() return log_str def logSnatch(searchResult): myDB = db.DBConnection("failed.db") logDate = datetime.datetime.today().strftime(dateFormat) release = prepareFailedName(searchResult.name) providerClass = searchResult.provider if providerClass is not None: provider = providerClass.name else:
def snatchEpisode(result, endStatus=SNATCHED): """ Contains the internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :param endStatus: the episode status that should be used for the episode object once it's snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high if sickbeard.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7): result.priority = 1 if re.search(r"(^|[\. _-])(proper|repack)([\. _-]|$)", result.name, re.I) != None: endStatus = SNATCHED_PROPER if result.url.startswith("magnet") or result.url.endswith("torrent"): result.resultType = "torrent" # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickbeard.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickbeard.NZB_METHOD == "sabnzbd": dlResult = sab.sendNZB(result) elif sickbeard.NZB_METHOD == "nzbget": is_proper = True if endStatus == SNATCHED_PROPER else False dlResult = nzbget.sendNZB(result, is_proper) else: logger.log(u"Unknown NZB action specified in config: " + sickbeard.NZB_METHOD, logger.ERROR) dlResult = False # TORRENTs can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickbeard.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith("magnet"): result.content = result.provider.getURL(result.url) if result.content or result.url.startswith("magnet"): client = clients.getClientIstance(sickbeard.TORRENT_METHOD)() dlResult = client.sendTORRENT(result) else: logger.log(u"Torrent file content is empty", logger.WARNING) dlResult = False else: logger.log(u"Unknown result type, unable to download it", logger.ERROR) dlResult = False if not dlResult: return False if sickbeard.USE_FAILED_DOWNLOADS: failed_history.logSnatch(result) ui.notifications.message("Episode snatched", result.name) history.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: notifiers.notify_snatch( curEpObj._format_pattern("%SN - %Sx%0E - %EN - %QN") + " from " + result.provider.name ) trakt_data.append((curEpObj.season, curEpObj.episode)) data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickbeard.USE_TRAKT and sickbeard.TRAKT_SYNC_WATCHLIST: logger.log( u"Add episodes, showid: indexerid " + str(result.show.indexerid) + ", Title " + str(result.show.name) + " to Traktv Watchlist", logger.DEBUG, ) if data: notifiers.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if len(sql_l) > 0: myDB = db.DBConnection() myDB.mass_action(sql_l) return True
try: ep_obj = show_obj.getEpisode(season, episode) with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() except exceptions.EpisodeNotFoundException, e: log_str += _log_helper(u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING) else: # Whole season for ep_obj in show_obj.getAllEpisodes(season): with ep_obj.lock: quality = Quality.splitCompositeStatus(ep_obj.status)[1] ep_obj.status = Quality.compositeStatus(FAILED, quality) ep_obj.saveToDB() return log_str def logSnatch(searchResult): myDB = db.DBConnection("failed.db") logDate = datetime.datetime.today().strftime(dateFormat) release = prepareFailedName(searchResult.name) providerClass = searchResult.provider if providerClass is not None: provider = providerClass.name else: provider = "unknown"
def snatchEpisode(result): # pylint: disable=too-many-branches, too-many-statements """ Internal logic necessary to actually "snatch" a result that has been found. :param result: SearchResult instance to be snatched. :return: boolean, True on success """ if result is None: return False result.priority = 0 # -1 = low, 0 = normal, 1 = high is_proper = False if sickbeard.ALLOW_HIGH_PRIORITY: # if it aired recently make it high priority for curEp in result.episodes: if datetime.date.today() - curEp.airdate <= datetime.timedelta(days=7): result.priority = 1 if result.proper_tags: logger.log(u'Found proper tags for {0}. Snatching as PROPER'.format(result.name), logger.DEBUG) is_proper = True endStatus = SNATCHED_PROPER else: endStatus = SNATCHED if result.url.startswith('magnet') or result.url.endswith('torrent'): result.resultType = 'torrent' # NZBs can be sent straight to SAB or saved to disk if result.resultType in ("nzb", "nzbdata"): if sickbeard.NZB_METHOD == "blackhole": dlResult = _downloadResult(result) elif sickbeard.NZB_METHOD == "sabnzbd": dlResult = sab.sendNZB(result) elif sickbeard.NZB_METHOD == "nzbget": dlResult = nzbget.sendNZB(result, is_proper) else: logger.log(u"Unknown NZB action specified in config: " + sickbeard.NZB_METHOD, logger.ERROR) dlResult = False # Torrents can be sent to clients or saved to disk elif result.resultType == "torrent": # torrents are saved to disk when blackhole mode if sickbeard.TORRENT_METHOD == "blackhole": dlResult = _downloadResult(result) else: if not result.content and not result.url.startswith('magnet'): if result.provider.login(): result.content = result.provider.get_url(result.url, returns='content') if result.content or result.url.startswith('magnet'): client = clients.get_client_instance(sickbeard.TORRENT_METHOD)() dlResult = client.send_torrent(result) else: logger.log(u"Torrent file content is empty", logger.WARNING) dlResult = False else: logger.log(u"Unknown result type, unable to download it (%r)" % result.resultType, logger.ERROR) dlResult = False if not dlResult: return False if sickbeard.USE_FAILED_DOWNLOADS: failed_history.logSnatch(result) ui.notifications.message('Episode snatched', result.name) history.logSnatch(result) # don't notify when we re-download an episode sql_l = [] trakt_data = [] for curEpObj in result.episodes: with curEpObj.lock: if isFirstBestMatch(result): curEpObj.status = Quality.compositeStatus(SNATCHED_BEST, result.quality) else: curEpObj.status = Quality.compositeStatus(endStatus, result.quality) sql_l.append(curEpObj.get_sql()) if curEpObj.status not in Quality.DOWNLOADED: try: notify_message = curEpObj.formatted_filename('%SN - %Sx%0E - %EN - %QN') if all([sickbeard.SEEDERS_LEECHERS_IN_NOTIFY, result.seeders not in (-1, None), result.leechers not in (-1, None)]): notifiers.notify_snatch("{0} with {1} seeders and {2} leechers from {3}".format (notify_message, result.seeders, result.leechers, result.provider.name), is_proper) else: notifiers.notify_snatch("{0} from {1}".format(notify_message, result.provider.name), is_proper) except Exception: # Without this, when notification fail, it crashes the snatch thread and Medusa will # keep snatching until notification is sent logger.log(u"Failed to send snatch notification. Error: {0}".format(e), logger.DEBUG) trakt_data.append((curEpObj.season, curEpObj.episode)) data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data) if sickbeard.USE_TRAKT and sickbeard.TRAKT_SYNC_WATCHLIST: logger.log(u"Add episodes, showid: indexerid " + str(result.show.indexerid) + u", Title " + str(result.show.name) + u" to Traktv Watchlist", logger.DEBUG) if data: notifiers.trakt_notifier.update_watchlist(result.show, data_episode=data, update="add") if sql_l: main_db_con = db.DBConnection() main_db_con.mass_action(sql_l) return True
def testNaming(self, show_name=None, ep_type=None, multi_ep_type=None, ep_name=None, sep_type=None, use_periods=None, quality=None, whichTest="single"): if show_name == None: show_name = sickbeard.NAMING_SHOW_NAME else: if show_name == "0": show_name = False else: show_name = True if ep_name == None: ep_name = sickbeard.NAMING_EP_NAME else: if ep_name == "0": ep_name = False else: ep_name = True if use_periods == None: use_periods = sickbeard.NAMING_USE_PERIODS else: if use_periods == "0": use_periods = False else: use_periods = True if quality == None: quality = sickbeard.NAMING_QUALITY else: if quality == "0": quality = False else: quality = True if ep_type == None: ep_type = sickbeard.NAMING_EP_TYPE else: ep_type = int(ep_type) if multi_ep_type == None: multi_ep_type = sickbeard.NAMING_MULTI_EP_TYPE else: multi_ep_type = int(multi_ep_type) if sep_type == None: sep_type = sickbeard.NAMING_SEP_TYPE else: sep_type = int(sep_type) class TVShow(): def __init__(self): self.name = "Show Name" self.genre = "Comedy" self.air_by_date = 0 # fake a TVShow (hack since new TVShow is coming anyway) class TVEpisode(tv.TVEpisode): def __init__(self, season, episode, name): self.relatedEps = [] self._name = name self._season = season self._episode = episode self.show = TVShow() # make a fake episode object ep = TVEpisode(1,2,"Ep Name") ep._status = Quality.compositeStatus(DOWNLOADED, Quality.HDTV) if whichTest == "multi": ep._name = "Ep Name (1)" secondEp = TVEpisode(1,3,"Ep Name (2)") ep.relatedEps.append(secondEp) # get the name name = ep.prettyName(show_name, ep_type, multi_ep_type, ep_name, sep_type, use_periods, quality) return name