def run(self): """Worker loop""" while 1: # Wait for work from the queue. Defers / waits if there is no new # work. if not self.dqueue.has_new_work(): self.working = False self.log.debug("worker %s: waiting for new task", self.id) self.task = yield self.dqueue.get() self.working = True self.dqueue.log_active = True if self.task is None: # kill all workers self.dqueue.put(None) return # Set task id self.seq = Worker.tasks Worker.tasks = Worker.tasks + 1 # Do the work try: self.log.debug("worker %s, task %d: picked up task" % (self.id, self.seq)) yield self.work(self.task) except Exception as e: for line in error.format_exception(): self.log.error("worker %s, task %d, : %s" % (self.id, self.seq, line)) finally: self.log.debug("worker %s, task %s: completed" % (self.id, self.seq)) self.task = None
def work(self, task): task.status = TaskStatus.PROCESSING tid = task.torrent_info.id try: # Store pointer to task self.task = task # Save worker info to task self.task.worker_id = self.id self.task.worker_seq = self.seq # Initialize logger adapter with task being worked on self.tlog.set_task(self.task) self.wlog.set_task(self.task) torrent = task.torrent name = TorrentInfo.get_display_name(torrent) id = TorrentInfo.get_id(torrent) self.tlog.info("post-process torrent(%s)" % name) if torrent is None: self.tlog.error( "torrent with id '%s' is no longer with us anymore." % id) defer.returnValue(False) result = yield self.call_sickbeard(task) task.status = TaskStatus.SUCCESS if result else TaskStatus.FAILED remove, remove_data = (self.config['remove'], self.config['remove_data']) if result and remove: self.tlog.info("schedule torrent(%s) for removal" % name) self.manager.remove(id, remove_data) else: self.tlog.info("*skip* schedule torrent(%s) for removal" % name) log_level = logging.INFO if result else logging.ERROR self.tlog.log(log_level, "post-process status %s" % task.status) except Exception as e: result = False task.status = TaskStatus.FAILED self.tlog.error('Exception occurred while processing torrent: ' + str(e)) for line in sb_err.format_exception(): self.tlog.error("%s" % line) finally: self.tasklog.add(task) defer.returnValue(result)
def work(self, task): task.status = TaskStatus.PROCESSING tid = task.torrent_info.id try: # Store pointer to task self.task = task # Save worker info to task self.task.worker_id = self.id self.task.worker_seq = self.seq # Initialize logger adapter with task being worked on self.tlog.set_task(self.task) self.wlog.set_task(self.task) torrent = task.torrent name = TorrentInfo.get_display_name(torrent) id = TorrentInfo.get_id(torrent) self.tlog.info("post-process torrent(%s)" % name) if torrent is None: self.tlog.error("torrent with id '%s' is no longer with us anymore." % id) defer.returnValue(False) result = yield self.call_sickbeard(task) task.status = TaskStatus.SUCCESS if result else TaskStatus.FAILED remove, remove_data = (self.config['remove'], self.config['remove_data']) if result and remove: self.tlog.info("schedule torrent(%s) for removal" % name) self.manager.remove(id, remove_data) else: self.tlog.info("*skip* schedule torrent(%s) for removal" % name) log_level = logging.INFO if result else logging.ERROR self.tlog.log(log_level, "post-process status %s" % task.status) except Exception as e: result = False task.status = TaskStatus.FAILED self.tlog.error('Exception occurred while processing torrent: ' + str(e)) for line in sb_err.format_exception(): self.tlog.error("%s" % line) finally: self.tasklog.add(task) defer.returnValue(result)
def call_sickbeard(self, task): """ Call Sickbeard to post-process torrent. Sickbeard post-processing API: dir : Directory to be post-processed by Sickbeard SINGLE-FILE torrent: download-complete-path MULTI-FILE torrent: download-complete-path/name (see spec below) nzbname : name of torrent to be post-processed by Sickbeard quiet : Output type 1 : no HTML output unset: HTML output by Sickbeard type : Sickbeard type of post-processing manual: Scheduled Post Processing (Processes files and dirs in TV_DOWNLOAD_DIR) auto : Script Post Processing (Processes files in a specified directory. Supports single file torrent.) force : Force already Post Processed Dir/Files (on | unset) is_priority: Mark Dir/Files as priority download (on | unset) (Replace the file, even if it already exists at higher quality) failed : Mark download as failed (1 or 0) method : copy, move, hardlink or symlink Sickbeard uses the "nzbname" to look for a "resource" in the post-processing directory(dir). A "resource" is either a single video file file, or a directory with video files. This to support SINGLE-FILE and MULTI-FILE torrents. During post-processing this "resource" is first looked up in the "history" table to quickly associate the "resource" to a tv-show, seasion, episode. In case no "resource" is available in the history, Sickbeard falls back to scan the post-processing directory(dir) for files and directories containing video files and use its default naming parse to extract tv-show, seasion, episode details from the directory and vide file names it discovered. This is very convenient in case we manually downloaded torrents and still want them to be post-processed with Sickbeard. Failed downloading uses a release name, stored in a separate history table in the SINGLE-FILE torrent spec: name: the filename. This is purely advisory. (string) MULTI-FILE torrent spec: name: the file path of the directory in which to store all the files. This is purely advisory. (string) Deluge follows the Torrent specifcation advisory. Returns: bool: True on success. False otherwise. """ try: torrent = task.torrent dir = TorrentInfo.get_saved_path(torrent) name = TorrentInfo.get_display_name(torrent) mode = TorrentInfo.get_mode(torrent) id = TorrentInfo.get_id(torrent) params = {} params['dir'] = dir.encode('utf-8') params['nzbName'] = name.encode('utf-8') params['quiet'] = 1 if self.config["quiet"] else None params['type'] = ProccessType.AUTOMATIC params['process_method'] = self.config["method"] if self.config[ "method"] != ProccessMethod.SB_DEFAULT else None params[ 'force'] = "on" if self.config["force"] or task.force else None params['is_priority'] = "on" if self.config[ "priority"] or task.priority else None params['failed'] = 1 if task.failed else 0 base_url = self.get_base_url() self.tlog.info("Contacting Sickbeard for post-processing") self.tlog.info("Torrent(nzbname): %s" % name) self.tlog.info("Using base URL : %s" % base_url) self.tlog.info("Username : %s" % self.config['username']) self.tlog.info("Request Type : %s" % params['type']) self.tlog.info("Directory : %s" % params['dir']) self.tlog.info("Mode : %s" % mode) methodDisplay = self.config["method"] if self.config[ "method"] != ProccessMethod.SB_DEFAULT else "Sickbeard Default" self.tlog.info("Method : %s" % methodDisplay) self.tlog.info("Priority : %s" % self.config["priority"]) self.tlog.info("Failed : %s" % params['failed']) self.tlog.info("Quiet : %s" % self.config["quiet"]) # Downloaded content directory/file must exist, even if it download actually failed, in order # for Sickbeard to be able to process the torrent self._ensure_saved_path(torrent) client = WebClient(self.wlog) result = yield client.get(base_url, args=params, username=self.config['username'], password=self.config['password']) except Exception as e: result = False self.tlog.error('Exception occurred while processing torrent: ' + str(e)) for line in sb_err.format_exception(): self.tlog.error("%s" % line) errors = 0 success = 0 if result: self.tlog.info("%s bytes received:" % len(result)) for line in result.split('\n'): self.tlog.info(" %s" % line) if line: for pattern in SickbeardWorker.ERRORS: errors += line.count(pattern) for pattern in SickbeardWorker.SUCCESS: success += line.count(pattern) succeeded = True if errors == 0 and success >= 1 else False if succeeded: self.tlog.info("Sickbeard post-processing torrent(%s) succeeded" % name) else: self.tlog.info("Sickbeard post-processing torrent(%s) failed" % name) defer.returnValue(succeeded)
def call_sickbeard(self, task): """ Call Sickbeard to post-process torrent. Sickbeard post-processing API: dir : Directory to be post-processed by Sickbeard SINGLE-FILE torrent: download-complete-path MULTI-FILE torrent: download-complete-path/name (see spec below) nzbname : name of torrent to be post-processed by Sickbeard quiet : Output type 1 : no HTML output unset: HTML output by Sickbeard type : Sickbeard type of post-processing manual: Scheduled Post Processing (Processes files and dirs in TV_DOWNLOAD_DIR) auto : Script Post Processing (Processes files in a specified directory. Supports single file torrent.) force : Force already Post Processed Dir/Files (on | unset) is_priority: Mark Dir/Files as priority download (on | unset) (Replace the file, even if it already exists at higher quality) failed : Mark download as failed (1 or 0) method : copy, move, hardlink or symlink Sickbeard uses the "nzbname" to look for a "resource" in the post-processing directory(dir). A "resource" is either a single video file file, or a directory with video files. This to support SINGLE-FILE and MULTI-FILE torrents. During post-processing this "resource" is first looked up in the "history" table to quickly associate the "resource" to a tv-show, seasion, episode. In case no "resource" is available in the history, Sickbeard falls back to scan the post-processing directory(dir) for files and directories containing video files and use its default naming parse to extract tv-show, seasion, episode details from the directory and vide file names it discovered. This is very convenient in case we manually downloaded torrents and still want them to be post-processed with Sickbeard. Failed downloading uses a release name, stored in a separate history table in the SINGLE-FILE torrent spec: name: the filename. This is purely advisory. (string) MULTI-FILE torrent spec: name: the file path of the directory in which to store all the files. This is purely advisory. (string) Deluge follows the Torrent specifcation advisory. Returns: bool: True on success. False otherwise. """ try: torrent = task.torrent dir = TorrentInfo.get_saved_path(torrent) name = TorrentInfo.get_display_name(torrent) mode = TorrentInfo.get_mode(torrent) id = TorrentInfo.get_id(torrent) params = {} params['dir'] = dir.encode('utf-8') params['nzbName'] = name.encode('utf-8') params['quiet'] = 1 if self.config["quiet"] else None params['type'] = ProccessType.AUTOMATIC params['process_method'] = self.config["method"] if self.config["method"] != ProccessMethod.SB_DEFAULT else None params['force'] = "on" if self.config["force"] or task.force else None params['is_priority'] = "on" if self.config["priority"] or task.priority else None params['failed'] = 1 if task.failed else 0 base_url = self.get_base_url() self.tlog.info("Contacting Sickbeard for post-processing") self.tlog.info("Torrent(nzbname): %s" % name) self.tlog.info("Using base URL : %s" % base_url) self.tlog.info("Username : %s" % self.config['username']) self.tlog.info("Request Type : %s" % params['type']) self.tlog.info("Directory : %s" % params['dir']) self.tlog.info("Mode : %s" % mode) methodDisplay = self.config["method"] if self.config["method"] != ProccessMethod.SB_DEFAULT else "Sickbeard Default" self.tlog.info("Method : %s" % methodDisplay) self.tlog.info("Priority : %s" % self.config["priority"]) self.tlog.info("Failed : %s" % params['failed']) self.tlog.info("Quiet : %s" % self.config["quiet"]) # Downloaded content directory/file must exist, even if it download actually failed, in order # for Sickbeard to be able to process the torrent self._ensure_saved_path(torrent); client = WebClient(self.wlog) result = yield client.get(base_url, args = params, username = self.config['username'], password = self.config['password']) except Exception as e: result = False self.tlog.error('Exception occurred while processing torrent: ' + str(e)) for line in sb_err.format_exception(): self.tlog.error("%s" % line) errors = 0 success = 0 if result: self.tlog.info("%s bytes received:" % len(result)) for line in result.split('\n'): self.tlog.info(" %s" % line) if line: for pattern in SickbeardWorker.ERRORS: errors += line.count(pattern) for pattern in SickbeardWorker.SUCCESS: success += line.count(pattern) succeeded = True if errors == 0 and success >= 1 else False if succeeded: self.tlog.info("Sickbeard post-processing torrent(%s) succeeded" % name) else: self.tlog.info("Sickbeard post-processing torrent(%s) failed" % name) defer.returnValue(succeeded)