def _add_new_db(self, season=0, episode=0): if self.db.show_exists(self.id): sql = '''UPDATE shows SET status="active", episode=:episode, season=:season WHERE thetvdb_series_id=:thetvdb_id;''' values = { 'thetvdb_id': self.id, 'episode': episode, 'season': season } msg = '%s is already in the db. Its status is now set to "active"' % self.seriesname else: sql = ''' INSERT INTO shows ( network_status, status, thetvdb_series_id, name, season, episode) VALUES (:network_status, :status, :thetvdb_id, :name, :season, :episode)''' values = {'network_status': self.status, 'status': 'active', 'thetvdb_id': self.id, 'name': self.seriesname, 'season': season, 'episode': episode} msg = '%s %s, added' % (self.seriesname, sxxexx(season, episode)) conn = sqlite3.connect(Config.db_file) curs = conn.cursor() curs.execute(sql, values) conn.commit() conn.close() return msg
def _add_new_db(self, season=0, episode=0): if self.db.show_exists(self.id): sql = '''UPDATE shows SET status="active", episode=:episode, season=:season WHERE thetvdb_series_id=:thetvdb_id;''' values = { 'thetvdb_id': self.id, 'episode': episode, 'season': season } msg = '%s is already in the db. Its status is now set to "active"' % self.seriesname else: sql = ''' INSERT INTO shows ( network_status, status, thetvdb_series_id, name, season, episode) VALUES (:network_status, :status, :thetvdb_id, :name, :season, :episode)''' values = {'network_status': self.status, 'status': 'active', 'thetvdb_id': self.id, 'name': self.seriesname, 'season': season, 'episode': episode} episode += 1 episode = str(episode) if season == 0: season += 1 season = str(season) msg = '%s %s added.' % (self.seriesname, sxxexx(season, episode)) DB.run_sql(sql, values) return msg
def magnet_filename(self): se_ep = sxxexx(self.season, self.episode) if se_ep: fullname = '%s %s.magnet' % (self.show_name, se_ep) else: fullname = '%s.magnet' % (self.show_name) fullname = fullname.replace(' ', '_') return fullname
def magnet_filename(self, chosen_show=None): se_ep = tu.sxxexx(self.season, self.episode) if se_ep: fullname = '%s %s.magnet' % (self.show_name, se_ep) fullname = fullname.replace(' ', '_') else: show_fname = self.show_name for f in self.episodes: if chosen_show == f[5]: show_fname = tu.clean_filename(f[0], strict=True) fullname = '%s.magnet' % (show_fname) return fullname
def magnet_filename(self, chosen_show=None): se_ep = tu.sxxexx(self.season, self.episode) if se_ep: fullname = '%s %s.magnet' % (self.show_name, se_ep) fullname = fullname.replace(' ', '_') else: show_fname = self.show_name for f in self.episodes: if chosen_show == f[5]: show_fname = tu.clean_filename(f[0], strict=True) fullname = '%s.magnet' % (show_fname) return fullname
def search(self, search_string, season=False, episode=False, idx=None): search_string = '%s %s' % (search_string.strip(), tvu.sxxexx(season, episode)) xml_fragment = self.retrieve_data(search_string, season, episode) if xml_fragment: data = self.format_data(xml_fragment, idx) else: data = [] return data
def search(self, search_string, season=False, episode=False, idx=None): search_string = '%s %s' % ( search_string.strip(), tvu.sxxexx(season, episode)) xml_fragment = self.retrieve_data(search_string, season, episode) if xml_fragment: data = self.format_data(xml_fragment, idx) else: data = [] return data
def search(self, search_string, season=False, episode=False): if season and episode: search_string = '%s %s' % (search_string, sxxexx(season, episode)) query = urllib.parse.quote(search_string) show_data = [] for try_url in self.provider_urls: url = '%s/rss/type/search/x/%s/' % (try_url, query) self.url = url parsed = feedparser.parse(url) if len(parsed['entries']) == 0: continue for show in parsed['entries']: if not show: continue if show['published_parsed']: dt = datetime.fromtimestamp( mktime(show['published_parsed'])) date = dt.strftime('%b %d/%Y') else: date = '-' size = show['size'] title = show['title'] seeds = show['seeds'] magnet = hash2magnet(show['hash'], title) show_data.append([ title, size, date, seeds, self.shortname, magnet ]) # return without trying any more urls, this one has data. return show_data # return the empty show_data empty array return show_data
def search(self, search_string, season=False, episode=False): if season and episode: search_string = '%s %s' % (search_string, sxxexx(season, episode)) query = urllib.parse.quote(search_string) socket.setdefaulttimeout(Config.timeout) show_data = [] for try_url in self.provider_urls: url = '%s/rss/type/search/x/%s/' % (try_url, query) self.url = url parsed = feedparser.parse(url) if len(parsed['entries']) == 0: continue for show in parsed['entries']: if not show: continue if show['published_parsed']: dt = datetime.fromtimestamp( mktime(show['published_parsed'])) date = dt.strftime('%b %d/%Y') else: date = '-' size = show['size'] title = show['title'] seeds = show['seeds'] magnet = hash2magnet(show['hash'], title) show_data.append( [title, size, date, seeds, self.shortname, magnet]) # return without trying any more urls, this one has data. return show_data # return the empty show_data empty array return show_data
def _add_new_db(self, season=0, episode=0): if self.db.show_exists(self.id): sql = '''UPDATE shows SET status="active", episode=:episode, season=:season WHERE thetvdb_series_id=:thetvdb_id;''' values = { 'thetvdb_id': self.id, 'episode': episode, 'season': season } msg = '%s is already in the db. Its status is now set to "active"' % self.seriesName else: sql = ''' INSERT INTO shows ( network_status, status, thetvdb_series_id, name, season, episode) VALUES (:network_status, :status, :thetvdb_id, :name, :season, :episode)''' values = { 'network_status': self.status, 'status': 'active', 'thetvdb_id': self.id, 'name': self.seriesName, 'season': season, 'episode': episode } episode += 1 episode = str(episode) if season == 0: season += 1 season = str(season) msg = '%s %s added.' % (self.seriesName, sxxexx(season, episode)) DB.run_sql(sql, values) return msg
def add_new(self, name): try: result = self.tvapi.search(name) except KeyError as e: click.echo( 'Show data returned from TheTVDB.com has an error in it.', err=True) sys.exit(1) if not result: click.echo('No show found.') return else: click.echo('Multiple shows found, type a number to select.') click.echo('Type "<ctrl> c" to cancel.') click.echo() indent = ' ' for index, show in enumerate(result): title = show['seriesname'] click.echo(' %2s. ' % (index + 1), nl=False) click.secho(title, bold=True) if 'overview' in show: click.echo(format_paragraphs( show['overview'], indent=indent)) if 'firstaired' in show: click.secho( '%sFirst aired: %s' % (indent, show['firstaired']), fg='green') click.echo() choice = click.prompt( 'Choose number (or [enter] for #1)', default=1, type=click.IntRange(min=1, max=len(result))) idchoice = choice - 1 show = result[idchoice] self.db_name = show['seriesname'] # name self._get_thetvdb_series_data() last_season = 1 last_episode = 0 for season in self.series: last_season = season for episode in self.series[season]: b_date = self.series[season][episode]['firstaired'] if not b_date: continue # some episodes have no broadcast date split_date = b_date.split('-') broadcast_date = datetime.datetime( int(split_date[0]), int(split_date[1]), int(split_date[2])) today = datetime.datetime.today() if broadcast_date > today: break last_episode = episode last_sxxexx = style(sxxexx(last_season, last_episode), bold=True) if int(last_season) == 1 and int(last_episode) == 0: se = 0 ep = 0 else: click.echo() click.echo('The last episode broadcast was %s.' % last_sxxexx) msg = 'Start downloading the [f]irst (or [enter]), [l]atest or season and episode?' start = click.prompt(msg, default='f') if start == 'f': se = ep = 0 elif start == 'l': se = last_season ep = last_episode else: try: se, ep = [int(i) for i in start.split()] except ValueError: sys.exit('Season and episode must be two numbers seperated by a space.') if ep > 0: ep -= 1 # episode in db is the NEXT episode msg = self._add_new_db(season=se, episode=ep) click.echo() click.echo(msg)
def search(self, search_string, season=False, episode=False, date_search=None, search_type='torrent'): """ Return an array of values: [ [ ['Title string', 'search url'], [head1, head2, head3, id], [head1-width, head2-width, head3-width], [head1-alignment, head2-alignment, head3-alignment] ], [ [<column 1 data>, <column 2 data>, <column 3 data>, <id>], [<column 1 data>, <column 2 data>, <column 3 data>, <id>], # etc... ] ] """ self.season = season self.episode = episode self.show_name = search_string self.search_type = search_type click.echo() if self.search_type == 'torrent': header = [ [search_string, ''], ['Name', 'Size', 'Date', 'Seeds', 'SE'], [0, 10, 12, 6, 2], ['<', '>', '<', '>', '<']] else: header = [ [search_string, ''], ['Name', 'Size', 'Date', 'SE'], [0, 10, 12, 3], ['<', '>', '<', '<']] if self.search_type == 'torrent': engines = self.torrent_engines elif self.search_type == 'nzb': engines = self.newsgroup_engines else: raise ValueError('search_type can only be "torrent" or "nzb"') # socket.setdefaulttimeout(5) # socket.setdefaulttimeout(0.1) episodes = [] with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: # For nzb's, the idx is needed so Provider.download knows # which engine was used. It's not needed for torrents # because there is no download method. res = { executor.submit( self.job, engine, search_string, season, episode, date_search, idx ): engine for idx, engine in enumerate(engines) } names = [i.name for i in engines] names.sort() names = [' %s ' % i for i in names] names = [tu.style(i, fg='white', bg='red') for i in names] for future in concurrent.futures.as_completed(res): results = future.result() finished_name = results[-1] for i, e in enumerate(names): e = click.unstyle(e).strip() if e == finished_name: e = ' %s ' % e names[i] = tu.style(e, fg='white', bg='green') if date_search: title = '%s %s' % (search_string.strip(), date_search) else: title = '%s %s' % (search_string.strip(), tu.sxxexx(season, episode)) title = title.ljust(Config.console_columns) click.echo(tu.style(title, bold=True)) click.echo(' '.join(names)) # move up two lines click.echo('[%sA' % 3) episodes = episodes + results[:-1] # go up 3 lines to remove the progress bar click.echo('[%sA' % 2) if self.search_type == 'torrent': self.sort_torrents(episodes) self.episodes = episodes # return search_results return [header] + [episodes]
def pretty_names(self, filename, torrent_hash, template=None): if not template: template = '{show}/{original}' fields = {} (fields['show'], fields['searchname'], fields['season'], fields['episode']) = DB.get_show_info(torrent_hash) fields['original'] = os.path.basename(filename) fields['s00e00'] = sxxexx(fields['season'], fields['episode']) fields['0x00'] = sxee(fields['season'], fields['episode']) fields['season'] = fields['season'].rjust(2, '0') fields['episode'] = fields['episode'].rjust(2, '0') if fields['searchname'] is None: fields['searchname'] = '' # search original filename for info fields['resolution'] = '' for res in Config.categories.resolution: if res.lower() in filename.lower(): fields['resolution'] = res fields['source'] = '' for srs in Config.categories.sources: if srs.lower() in filename.lower(): fields['source'] = srs fields['codec'] = '' for cod in Config.categories.codecs: if cod.lower() in filename.lower(): fields['codec'] = cod fields['audio'] = '' for aud in Config.categories.audio: if aud.lower() in filename.lower(): fields['audio'] = aud # short cut tags all = [ fields['show'], fields['s00e00'], fields['resolution'], fields['source'], fields['codec'], fields['audio'] ] all = [i for i in all if i] # remove empty fields['all'] = ' '.join(all) ext = '' if os.path.isfile(filename): ext = os.path.splitext(filename)[-1] broke = re.split('({.*?})', template) if not broke[-1]: broke = broke[:-1] new = [] is_section = False for section in broke: if section.startswith('{'): chunks = section.strip('{}').split('|') field = chunks[0].lower() filters = [i.lower() for i in chunks[1:]] try: if not fields[field]: continue except KeyError: continue complete = self.format(fields[field], filters) new.append(complete) is_section = True else: new.append(section) is_section = False # remove adjacent duplicates new = [i[0] for i in itertools.groupby(new)] if not is_section: new = new[:-1] new.append(ext) full = ''.join(new) full = os.path.normpath(full) return full
def search(self, search_string, season=False, episode=False, date_search=None, search_type='torrent'): """ Return an array of values: [ [ ['Title string', 'search url'], [head1, head2, head3, id], [head1-width, head2-width, head3-width], [head1-alignment, head2-alignment, head3-alignment] ], [ [<column 1 data>, <column 2 data>, <column 3 data>, <id>], [<column 1 data>, <column 2 data>, <column 3 data>, <id>], # etc... ] ] """ self.season = season self.episode = episode self.show_name = search_string self.search_type = search_type click.echo() if self.search_type == 'torrent': header = [[search_string, ''], ['Name', 'Size', 'Date', 'Seeds', 'SE'], [0, 10, 12, 6, 2], ['<', '>', '<', '>', '<']] else: header = [[search_string, ''], ['Name', 'Size', 'Date', 'SE'], [0, 10, 12, 3], ['<', '>', '<', '<']] if self.search_type == 'torrent': engines = self.torrent_engines elif self.search_type == 'nzb': engines = self.newsgroup_engines else: raise ValueError('search_type can only be "torrent" or "nzb"') socket.setdefaulttimeout(10) # socket.setdefaulttimeout(0.1) episodes = [] with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: # For nzb's, the idx is needed so Provider.download knows # which engine was used. It's not needed for torrents # because there is no download method. res = { executor.submit(self.job, engine, search_string, season, episode, date_search, idx): engine for idx, engine in enumerate(engines) } names = [i.name for i in engines] names.sort() names = [' %s ' % i for i in names] names = [tu.style(i, fg='white', bg='red') for i in names] for future in concurrent.futures.as_completed(res): results = future.result() finished_name = results[-1] for i, e in enumerate(names): e = click.unstyle(e).strip() if e == finished_name: e = ' %s ' % e names[i] = tu.style(e, fg='white', bg='green') if date_search: title = '%s %s' % (search_string.strip(), date_search) else: title = '%s %s' % (search_string.strip(), tu.sxxexx(season, episode)) title = title.ljust(Config.console_columns) click.echo(tu.style(title, bold=True)) click.echo(' '.join(names)) # move up two lines click.echo('[%sA' % 3) episodes = episodes + results[:-1] # go up 3 lines to remove the progress bar click.echo('[%sA' % 2) if self.search_type == 'torrent': self.sort_torrents(episodes) if Config.filter_list: episodes = [i for i in episodes if self.filter_episode(i)] self.episodes = episodes # return search_results return [header] + [episodes]
def add_new(self, name): try: result = self.tvapi.search(name) except KeyError as e: click.echo( 'Show data returned from TheTVDB.com has an error in it.', err=True) sys.exit(1) if not result: click.echo('No show found.') return else: click.echo('Multiple shows found, type a number to select.') click.echo('Type "<ctrl> c" to cancel.') click.echo() indent = ' ' for index, show in enumerate(result): title = show['seriesName'] click.echo(' %2s. ' % (index + 1), nl=False) click.secho(title, bold=True) if 'overview' in show: click.echo( format_paragraphs(show['overview'], indent=indent)) if 'firstaired' in show: click.secho('%sFirst aired: %s' % (indent, show['firstaired']), fg='green') click.echo() choice = click.prompt('Choose number (or [enter] for #1)', default=1, type=click.IntRange(min=1, max=len(result))) idchoice = choice - 1 show = result[idchoice] self.db_name = show['seriesName'] # name self._get_thetvdb_series_data() last_season = 1 last_episode = 0 for season in self.series: last_season = season for episode in self.series[season]: b_date = self.series[season][episode]['firstaired'] if not b_date: continue # some episodes have no broadcast date split_date = b_date.split('-') broadcast_date = datetime.datetime(int(split_date[0]), int(split_date[1]), int(split_date[2])) today = datetime.datetime.today() if broadcast_date > today: break last_episode = episode last_sxxexx = style(sxxexx(last_season, last_episode), bold=True) if int(last_season) == 1 and int(last_episode) == 0: se = 0 ep = 0 else: click.echo() click.echo('The last episode broadcast was %s.' % last_sxxexx) msg = 'Start downloading the [f]irst (or [enter]), [l]atest or season and episode?' start = click.prompt(msg, default='f') if start == 'f': se = ep = 0 elif start == 'l': se = last_season ep = last_episode else: try: se, ep = [int(i) for i in start.split()] except ValueError: sys.exit( 'Season and episode must be two numbers seperated by a space.' ) if ep > 0: ep -= 1 # episode in db is the NEXT episode msg = self._add_new_db(season=se, episode=ep) click.echo() click.echo(msg)
def pretty_names(self, filename, torrent_hash, template=None): if not template: template = "{show}/{original}" fields = {} (fields["show"], fields["searchname"], fields["season"], fields["episode"]) = DB.get_show_info(torrent_hash) fields["original"] = os.path.basename(filename) fields["s00e00"] = sxxexx(fields["season"], fields["episode"]) fields["0x00"] = sxee(fields["season"], fields["episode"]) fields["season"] = fields["season"].rjust(2, "0") fields["episode"] = fields["episode"].rjust(2, "0") if fields["searchname"] is None: fields["searchname"] = "" # search original filename for info fields["resolution"] = "" for res in Config.categories.resolution: if res.lower() in filename.lower(): fields["resolution"] = res fields["source"] = "" for srs in Config.categories.sources: if srs.lower() in filename.lower(): fields["source"] = srs fields["codec"] = "" for cod in Config.categories.codecs: if cod.lower() in filename.lower(): fields["codec"] = cod fields["audio"] = "" for aud in Config.categories.audio: if aud.lower() in filename.lower(): fields["audio"] = aud # short cut tags all = [ fields["show"], fields["s00e00"], fields["resolution"], fields["source"], fields["codec"], fields["audio"], ] all = [i for i in all if i] # remove empty fields["all"] = " ".join(all) ext = "" if os.path.isfile(filename): ext = os.path.splitext(filename)[-1] broke = re.split("({.*?})", template) if not broke[-1]: broke = broke[:-1] new = [] is_section = False for section in broke: if section.startswith("{"): chunks = section.strip("{}").split("|") field = chunks[0].lower() filters = [i.lower() for i in chunks[1:]] try: if not fields[field]: continue except KeyError: continue complete = self.format(fields[field], filters) new.append(complete) is_section = True else: new.append(section) is_section = False # remove adjacent duplicates new = [i[0] for i in itertools.groupby(new)] if not is_section: new = new[:-1] new.append(ext) full = "".join(new) full = os.path.normpath(full) return full
def add_new(self, name): result = self.tvapi.search(name) if len(result) > 1: click.echo('Multiple shows found, type a number to select.') click.echo('Type "<ctrl> c" to cancel.') click.echo() for index, show in enumerate(result): click.echo(' %s. %s' % (index + 1, show['seriesname'])) click.echo() choice = click.prompt( 'Choose number', default=1, type=click.IntRange(min=1, max=len(result))) idchoice = choice - 1 if idchoice not in range(len(result)): sys.exit('Invalid choice: %s' % choice) show = result[idchoice] elif not result: click.echo('No show found.') return else: show = result[0] self.db_name = show['seriesname'] # name self._get_thetvdb_series_data() indent = ' ' if not self.show_exists: sys.exit() click.echo() click.echo(self.seriesname) click.echo('-' * len(self.seriesname)) if self.overview: click.echo(textwrap.fill(self.overview, initial_indent=indent, subsequent_indent=indent)) else: click.echo('No description provided.') click.echo() click.echo('%sFirst aired: %s' % (indent, self.firstaired)) click.echo('%sStatus: %s' % (indent, self.status)) click.echo() click.echo('Is this the correct show? [y/n]', nl=False) correct = click.getchar(echo=False) try: # this is nessesary for windows correct = correct.decode('utf-8') except AttributeError: pass click.echo(' %s' % correct) if str(correct) != 'y': click.echo('Not added') return last_season = 1 last_episode = 0 for season in self.series: last_season = season for episode in self.series[season]: b_date = self.series[season][episode]['firstaired'] if not b_date: continue # some episodes have no broadcast date split_date = b_date.split('-') broadcast_date = datetime.datetime( int(split_date[0]), int(split_date[1]), int(split_date[2])) today = datetime.datetime.today() if broadcast_date > today: break last_episode = episode last_sxxexx = sxxexx(last_season, last_episode) click.echo() click.echo('The last episode broadcast was %s.' % last_sxxexx) click.echo('Start downloading the [f]irst, [l]atest or season and episode?') msg = 'Type "f", "l" or a season and episode number' start = click.prompt(msg) if start == 'f': se = ep = 0 elif start == 'l': se = last_season ep = last_episode else: try: se, ep = [int(i) for i in start.split()] except ValueError: sys.exit('Season and episode must be two numbers seperated by a space') if ep > 0: ep -= 1 # episode in db is the NEXT episode msg = self._add_new_db(season=se, episode=ep) click.echo() click.echo(msg)