예제 #1
0
파일: show.py 프로젝트: getecer/tv-overlord
    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
예제 #2
0
    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
예제 #3
0
 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
예제 #4
0
 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
예제 #5
0
 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
예제 #6
0
파일: nzb.py 프로젝트: shrx/tv-overlord
    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
예제 #7
0
    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
예제 #8
0
    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
예제 #9
0
    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
예제 #10
0
    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
예제 #11
0
    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)
예제 #12
0
    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]
예제 #13
0
    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
예제 #14
0
    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]
예제 #15
0
    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)
예제 #16
0
    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
예제 #17
0
파일: show.py 프로젝트: getecer/tv-overlord
    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)