Exemple #1
0
def main():
    # instantiate DataFile-based objects
    config = Config()
    feeds = Feeds()

    # update fields in help menu text
    for field in config:
        if "{%s}" % field in castero.__help__:
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s}" % field,
                    config[field].ljust(9)
                )
        elif "{%s|" % field in castero.__help__:
            field2 = castero.__help__.split("{%s|" % field)[1].split("}")[0]
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s|%s}" % (field, field2),
                    ("%s or %s" % (config[field], config[field2])).ljust(9)
                )

    # check if user is running the client with an info flag
    info_flags = {'help': ['-h', '--help'], 'version': ['-v', '--version']}
    if sys.argv[len(sys.argv) - 1] in info_flags['help']:
        print(castero.__help__)
        sys.exit(0)
    elif sys.argv[len(sys.argv) - 1] in info_flags['version']:
        print(castero.__version__)
        sys.exit(0)

    # check whether dependencies are met
    Player.check_dependencies()

    # instantiate the display object
    stdscr = curses.initscr()
    display = Display(stdscr, config, feeds)
    display.clear()
    display.update_parent_dimensions()

    # check if we need to start reloading
    if helpers.is_true(config['reload_on_start']):
        reload_thread = threading.Thread(target=feeds.reload, args=[display])
        reload_thread.start()

    # run initial display operations
    display.display()
    display.update()
    display.refresh()

    # core loop for the client
    running = True
    while running:
        display.display()
        display.update()
        display.refresh()
        char = display.getch()
        if char != -1:
            running = display.handle_input(char)

    sys.exit(0)
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.

        Overrides method from Perspective; see documentation in that class.
        """
        # clear dynamic menu headers
        self._downloaded_window.addstr(
            0, 0, " " * self._downloaded_window.getmaxyx()[1])

        # add window headers
        self._downloaded_window.addstr(0, 0, self._downloaded_menu.title,
                                       curses.color_pair(7) | curses.A_BOLD)
        self._metadata_window.addstr(0, 0, "Metadata",
                                     curses.color_pair(7) | curses.A_BOLD)

        # add window borders
        self._downloaded_window.hline(1, 0, 0,
                                      self._downloaded_window.getmaxyx()[1],
                                      curses.ACS_HLINE | curses.color_pair(8))
        self._metadata_window.hline(1, 0, 0,
                                    self._metadata_window.getmaxyx()[1] - 1,
                                    curses.ACS_HLINE | curses.color_pair(8))
        if not helpers.is_true(Config["disable_vertical_borders"]):
            self._downloaded_window.vline(
                0,
                self._downloaded_window.getmaxyx()[1] - 1, 0,
                self._downloaded_window.getmaxyx()[0] - 2,
                curses.ACS_VLINE | curses.color_pair(8))

        # display menu content
        self._downloaded_menu.display()

        # draw metadata
        if not self._metadata_updated:
            self._draw_metadata(self._metadata_window)
Exemple #3
0
    def metadata(self) -> str:
        """str: the user-displayed metadata of the episode"""
        description = helpers.html_to_plain(self.description) if \
            helpers.is_true(Config["clean_html_descriptions"]) else \
            self.description
        description = description.replace('\n', '')
        downloaded = "Episode downloaded and available for offline playback." \
            if self.downloaded else "Episode not downloaded."

        return \
            "!cb{title}\n" \
            "{pubdate}\n\n" \
            "{link}\n\n" \
            "!cbCopyright:\n" \
            "{copyright}\n\n" \
            "!cbDownloaded:\n" \
            "{downloaded}\n\n" \
            "!cbDescription:\n" \
            "{description}\n".format(
                title=self.title,
                pubdate=self.pubdate,
                link=self.link,
                copyright=self.copyright,
                downloaded=downloaded,
                description=description)
Exemple #4
0
    def metadata(self) -> str:
        """str: the user-displayed metadata of the episode"""
        description = (helpers.html_to_plain(self.description)
                       if helpers.is_true(Config["clean_html_descriptions"])
                       else self.description)
        description = description.replace("\n", "")
        progress = helpers.seconds_to_time(self.progress /
                                           constants.MILLISECONDS_IN_SECOND)
        downloaded = ("Episode downloaded and available for offline playback."
                      if self.downloaded else "Episode not downloaded.")
        metadata = ("!cb{title}\n"
                    "{pubdate}\n\n"
                    "{link}\n\n"
                    "!cbCopyright:\n"
                    "{copyright}\n\n"
                    "!cbDownloaded:\n"
                    "{downloaded}\n\n"
                    "!cbDescription:\n"
                    "{description}\n\n"
                    "!cbTime Played:\n"
                    "{progress}\n".format(
                        title=self.title,
                        pubdate=self.pubdate,
                        link=self.link,
                        copyright=self.copyright,
                        downloaded=downloaded,
                        description=description,
                        progress=progress,
                    ))

        return metadata
Exemple #5
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.

        Overrides method from Perspective; see documentation in that class.
        """
        # add window titles
        self._feed_window.attron(curses.A_BOLD)
        self._episode_window.attron(curses.A_BOLD)
        self._metadata_window.attron(curses.A_BOLD)
        self._feed_window.addstr(0, 0, "Feeds")
        self._episode_window.addstr(0, 0, "Episodes")
        self._metadata_window.addstr(0, 0, "Metadata")

        # add window borders
        self._feed_window.hline(1, 0, 0, self._feed_window.getmaxyx()[1])

        self._episode_window.hline(1, 0, 0, self._episode_window.getmaxyx()[1])
        self._metadata_window.hline(1, 0, 0,
                                    self._metadata_window.getmaxyx()[1] - 1)
        if not helpers.is_true(Config["disable_vertical_borders"]):
            self._feed_window.vline(0,
                                    self._feed_window.getmaxyx()[1] - 1, 0,
                                    self._feed_window.getmaxyx()[0] - 2)
            self._episode_window.vline(0,
                                       self._episode_window.getmaxyx()[1] - 1,
                                       0,
                                       self._episode_window.getmaxyx()[0] - 2)

        # display menu content
        self._feed_menu.display()
        self._episode_menu.display()

        # draw metadata
        if not self._metadata_updated:
            self._draw_metadata(self._metadata_window)
Exemple #6
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders."""
        # clear dynamic menu headers
        self._episode_window.addstr(0, 0, " " * self._episode_window.getmaxyx()[1])

        # add window headers
        self._episode_window.addstr(0, 0, self._episode_menu.title, curses.color_pair(7) | curses.A_BOLD)
        self._metadata_window.addstr(0, 0, "Metadata", curses.color_pair(7) | curses.A_BOLD)

        # add window borders
        self._episode_window.hline(
            1, 0, 0, self._episode_window.getmaxyx()[1], curses.ACS_HLINE | curses.color_pair(8)
        )
        self._metadata_window.hline(
            1, 0, 0, self._metadata_window.getmaxyx()[1] - 1, curses.ACS_HLINE | curses.color_pair(8)
        )
        if not helpers.is_true(Config["disable_vertical_borders"]):
            self._episode_window.vline(
                0,
                self._episode_window.getmaxyx()[1] - 1,
                0,
                self._episode_window.getmaxyx()[0] - 2,
                curses.ACS_VLINE | curses.color_pair(8),
            )

        # draw metadata
        if not self._metadata_updated:
            self._draw_metadata(self._metadata_window)
            self._metadata_window.refresh()
            self._metadata_updated = True

        self._episode_window.refresh()
Exemple #7
0
    def __init__(self):
        """
        If the database file does not exist but the old Feeds file does, we
        create the database using the old format.
        """
        existed = os.path.exists(self.PATH)
        DataFile.ensure_path(self.PATH)

        self._using_memory = not helpers.is_true(
            Config["restrict_memory_usage"])

        file_conn = sqlite3.connect(self.PATH, check_same_thread=False)
        file_conn.execute("PRAGMA foreign_keys = ON")

        if self._using_memory:
            memory_conn = sqlite3.connect(":memory:", check_same_thread=False)
            self._copy_database(file_conn, memory_conn)
            self._conn = memory_conn
        else:
            self._conn = file_conn

        if not existed and os.path.exists(self.OLD_PATH):
            self._create_from_old_feeds()

        self.migrate()
Exemple #8
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.

        Overrides method from Perspective; see documentation in that class.
        """
        # add window titles
        self._queue_window.attron(curses.A_BOLD)
        self._metadata_window.attron(curses.A_BOLD)
        self._queue_window.addstr(0, 0, "Queue")
        self._metadata_window.addstr(0, 0, "Metadata")

        # add window borders
        self._queue_window.hline(1, 0, 0, self._queue_window.getmaxyx()[1])
        self._metadata_window.hline(1, 0, 0,
                                    self._metadata_window.getmaxyx()[1] - 1)
        if not helpers.is_true(Config["disable_vertical_borders"]):
            self._queue_window.vline(0,
                                     self._queue_window.getmaxyx()[1] - 1, 0,
                                     self._queue_window.getmaxyx()[0] - 2)

        # display menu content
        self._queue_menu.display()

        # draw metadata
        queue = self._display.queue
        if not self._metadata_updated and queue.length > 0:
            selected_index = self._queue_menu.selected_index
            episode = queue[selected_index].episode
            self._draw_metadata(self._metadata_window, episode=episode)
Exemple #9
0
 def __init__(self, display) -> None:
     super().__init__(display)
     self._active_window = 0
     self._feed_window = None
     self._episode_window = None
     self._feed_menu = None
     self._episode_menu = None
     self._queue_unplayed_feed_episodes = helpers.is_true(
         Config["add_only_unplayed_episodes"])
Exemple #10
0
 def __init__(self, display) -> None:
     """
     Overrides method from Perspective; see documentation in that class.
     """
     super().__init__(display)
     self._active_window = 0
     self._feed_window = None
     self._episode_window = None
     self._feed_menu = None
     self._episode_menu = None
     self._queue_unplayed_feed_episodes = helpers.is_true(
         Config["add_only_unplayed_episodes"])
Exemple #11
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.
        """
        # check if the screen size has changed
        self.update_parent_dimensions()

        # check to see if menu contents have been invalidated
        if not self.menus_valid:
            for perspective_id in self._perspectives:
                self._perspectives[perspective_id].update_menus()
            self.menus_valid = True

        # add header
        playing_str = castero.__title__
        if self._queue.first is not None:
            state = self._queue.first.state
            playing_str = ["Stopped", "Playing", "Paused"][state] + \
                ": %s" % self._queue.first.title
            if self._queue.length > 1:
                playing_str += " (+%d in queue)" % (self._queue.length - 1)

            if helpers.is_true(Config["right_align_time"]):
                playing_str += ("[%s]" % self._queue.first.time_str).rjust(
                    self._header_window.getmaxyx()[1] - len(playing_str))
            else:
                playing_str += " [%s]" % self._queue.first.time_str

        self._header_window.addstr(0, 0,
                                   " " * self._header_window.getmaxyx()[1])
        self._header_window.addstr(0, 0, playing_str,
                                   curses.color_pair(6) | curses.A_BOLD)

        # add footer
        footer_str = "%sPress %s for help" % (
            self._status + " -- " if len(self._status) > 0 else "",
            Config["key_help"])
        footer_str = footer_str[:self._footer_window.getmaxyx()[1] - 1]
        max_width = self._footer_window.getmaxyx()[1] - 1
        self._footer_window.addstr(1, 0,
                                   footer_str.ljust(max_width)[:max_width],
                                   curses.color_pair(6) | curses.A_BOLD)

        # add window borders
        self._header_window.hline(1, 0,
                                  0, self._header_window.getmaxyx()[1],
                                  curses.ACS_HLINE | curses.color_pair(8))
        self._footer_window.hline(0, 0,
                                  0, self._footer_window.getmaxyx()[1],
                                  curses.ACS_HLINE | curses.color_pair(8))

        # update display for current perspective
        self._perspectives[self._active_perspective].display()
Exemple #12
0
    def metadata(self) -> str:
        """str: the user-displayed metadata of the feed"""
        description = helpers.html_to_plain(self.description) if \
            helpers.is_true(Config["clean_html_descriptions"]) else \
            self.description
        description = description.replace('\n', '')

        return \
            f"\cb{self.title}\n" \
            f"{self.last_build_date}\n\n" \
            f"{self.link}\n\n" \
            f"\cbDescription:\n" \
            f"{description}\n\n" \
            f"\cbCopyright:\n" \
            f"{self.copyright}\n"
Exemple #13
0
    def _delete_feed(self) -> None:
        """Deletes the current selected feed.

        If the delete_feed_confirmation config option is true, this method will
        first ask for y/n confirmation before deleting the feed.
        """
        if self._active_window == 0:
            should_delete = True
            if helpers.is_true(self._config["delete_feed_confirmation"]):
                should_delete = self._get_y_n(
                    "Are you sure you want to delete this feed? (y/n): ")
            if should_delete:
                deleted = self._feeds.del_at(self._feed_menu.selected_index)
                if deleted:
                    self.create_menus()
                    self._feeds.write()
                    self.change_status("Feed successfully deleted")
Exemple #14
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.

        Overrides method from Perspective; see documentation in that class.
        """
        # add window titles
        self._feed_window.attron(curses.A_BOLD)
        self._episode_window.attron(curses.A_BOLD)
        self._metadata_window.attron(curses.A_BOLD)
        self._feed_window.addstr(0, 0, "Feeds")
        self._episode_window.addstr(0, 0, "Episodes")
        self._metadata_window.addstr(0, 0, "Metadata")

        # add window borders
        self._feed_window.hline(1, 0, 0, self._feed_window.getmaxyx()[1])

        self._episode_window.hline(1, 0, 0, self._episode_window.getmaxyx()[1])
        self._metadata_window.hline(1, 0, 0,
                                    self._metadata_window.getmaxyx()[1] - 1)
        if not helpers.is_true(Config["disable_vertical_borders"]):
            self._feed_window.vline(0,
                                    self._feed_window.getmaxyx()[1] - 1, 0,
                                    self._feed_window.getmaxyx()[0] - 2)
            self._episode_window.vline(0,
                                       self._episode_window.getmaxyx()[1] - 1,
                                       0,
                                       self._episode_window.getmaxyx()[0] - 2)

        # display menu content
        self._feed_menu.display()
        self._episode_menu.display()

        # draw metadata
        if not self._metadata_updated:
            selected_feed_index = self._feed_menu.selected_index
            feed = self._display.feeds.at(selected_feed_index)
            if feed is not None:
                if self._active_window == 0:
                    self._draw_metadata(self._metadata_window, feed=feed)
                elif self._active_window == 1:
                    selected_episode_index = self._episode_menu.selected_index
                    if 0 <= selected_episode_index < len(feed.episodes):
                        episode = feed.episodes[selected_episode_index]
                        self._draw_metadata(self._metadata_window,
                                            episode=episode)
Exemple #15
0
    def delete_feed(self, feed: Feed) -> None:
        """Deletes the given feed from the database.

        If the delete_feed_confirmation config option is true, this method will
        first ask for y/n confirmation before deleting the feed.

        Deleting a feed also deletes all downloaded/saved episodes.

        :param feed the Feed to delete, which can be None
        """
        if feed is not None:
            should_delete = True
            if helpers.is_true(Config["delete_feed_confirmation"]):
                should_delete = self._get_y_n(
                    "Are you sure you want to delete this feed? (y/n): ")
            if should_delete:
                self.database.delete_feed(feed)
                self.menus_valid = False
                self.change_status("Feed successfully deleted")
Exemple #16
0
    def delete_feed(self, index) -> None:
        """Deletes the feed at the given index.

        If the delete_feed_confirmation config option is true, this method will
        first ask for y/n confirmation before deleting the feed.

        Deleting a feed also deletes all downloaded/saved episodes.

        Args:
            index: the index of the feed to delete within self._feeds
        """
        should_delete = True
        if helpers.is_true(Config["delete_feed_confirmation"]):
            should_delete = self._get_y_n(
                "Are you sure you want to delete this feed? (y/n): ")
        if should_delete:
            deleted = self._feeds.del_at(index)
            if deleted:
                self._feeds.write()
                self.create_menus()
                self.change_status("Feed successfully deleted")
Exemple #17
0
def main():
    # check if user is running the client with an info flag
    info_flags = {'help': ['-h', '--help'], 'version': ['-v', '--version']}
    if sys.argv[len(sys.argv) - 1] in info_flags['help']:
        print(castero.__help__)
        sys.exit(0)
    elif sys.argv[len(sys.argv) - 1] in info_flags['version']:
        print(castero.__version__)
        sys.exit(0)

    # check whether dependencies are met
    Player.check_dependencies()

    # instantiate DataFile-based objects
    config = Config()
    feeds = Feeds()

    # instantiate the display object
    stdscr = curses.initscr()
    display = Display(stdscr, config, feeds)
    display.clear()
    display.update_parent_dimensions()

    # check if we need to start reloading
    if helpers.is_true(config['reload_on_start']):
        reload_thread = threading.Thread(target=feeds.reload, args=[display])
        reload_thread.start()

    # core loop for the client
    running = True
    while running:
        display.display()
        display.update()
        display.refresh()
        char = display.getch()
        if char != -1:
            running = display.handle_input(char)

    sys.exit(0)
Exemple #18
0
    def metadata(self) -> str:
        """str: the user-displayed metadata of the feed"""
        description = (
            helpers.html_to_plain(self.description)
            if helpers.is_true(Config["clean_html_descriptions"])
            else self.description
        )
        description = description.replace("\n", "")

        return (
            "!cb{title}\n"
            "{last_build_date}\n\n"
            "{link}\n\n"
            "!cbCopyright:\n"
            "{copyright}\n\n"
            "!cbDescription:\n"
            "{description}\n".format(
                title=self.title,
                last_build_date=self.last_build_date,
                link=self.link,
                copyright=self.copyright,
                description=description,
            )
        )
Exemple #19
0
    def display(self) -> None:
        """Draws all windows and sub-features, including titles and borders.
        """
        # check if the screen size has changed
        self.update_parent_dimensions()

        # check to see if menu contents have been invalidated
        if not self.menus_valid:
            for perspective_id in self._perspectives:
                self._perspectives[perspective_id].update_menus()
            self.menus_valid = True

        # update window colors
        self._header_window.bkgd(curses.color_pair(4))
        self._footer_window.bkgd(curses.color_pair(4))

        # add header
        playing_str = castero.__title__
        if self._queue.first is not None:
            state = self._queue.first.state
            playing_str = ["Stopped", "Playing", "Paused"][state] + \
                ": %s" % self._queue.first.title
            if self._queue.length > 1:
                playing_str += " (+%d in queue)" % (self._queue.length - 1)

            if helpers.is_true(Config["right_align_time"]):
                playing_str += ("[%s]" % self._queue.first.time_str
                                ).rjust(self._header_window.getmaxyx()[1] -
                                        len(playing_str))
            else:
                playing_str += " [%s]" % self._queue.first.time_str

        self._header_window.attron(curses.A_BOLD)
        self._header_window.addstr(0, 0,
                                   " " * self._header_window.getmaxyx()[1])
        self._header_window.addstr(0, 0, playing_str)

        # add footer
        footer_str = ""
        if self._status == "" and not \
                helpers.is_true(Config["disable_default_status"]):
            feeds = self.database.feeds()
            if len(feeds) > 0:
                total_feeds = len(feeds)
                lengths_of_feeds = \
                    [len(self.database.episodes(feed)) for feed in feeds]
                total_episodes = sum(lengths_of_feeds)
                median_episodes = helpers.median(lengths_of_feeds)

                footer_str += "Found %d feeds with %d total episodes (avg." \
                              " %d episodes, med. %d)" % (
                                  total_feeds,
                                  total_episodes,
                                  total_episodes / total_feeds,
                                  median_episodes
                              )
            else:
                footer_str += "No feeds added"
        else:
            footer_str = self._status

        if footer_str != "":
            footer_str += " -- Press %s for help" % Config["key_help"]

        self._footer_window.attron(curses.A_BOLD)
        footer_str = footer_str[:self._footer_window.getmaxyx()[1] - 1]
        self._footer_window.addstr(1, 0, footer_str)

        # add window borders
        self._header_window.hline(1, 0, 0, self._header_window.getmaxyx()[1])
        self._footer_window.hline(0, 0, 0, self._footer_window.getmaxyx()[1])

        # update display for current perspective
        self._perspectives[self._active_perspective].display()
Exemple #20
0
    def _draw_metadata(self, window, feed=None, episode=None) -> None:
        """Draws the metadata of the selected feed/episode onto the window.

        Exactly one of feed or episode must be specified.

        Args:
            window: the curses window which will display the metadata
            feed: (optional) the Feed whose metadata will be displayed
            episode: (optional) the Episode whose metadata will be displayed
        """
        assert window is not None
        assert feed != episode and (feed is None or episode is None)

        output_lines = []  # 2D array, each element is [attr, str]
        max_lines = window.getmaxyx()[0] - 2
        max_line_width = window.getmaxyx()[1] - 1

        # clear the window by drawing blank lines
        for y in range(2, window.getmaxyx()[0]):
            window.addstr(y, 0, " " * max_line_width)

        if feed is not None:
            # draw feed title
            self._append_metadata_lines(
                window, feed.title, output_lines, attr=curses.A_BOLD)
            # draw feed lastBuildDate
            self._append_metadata_lines(
                window, feed.last_build_date, output_lines, add_blank=True)
            # draw feed link
            self._append_metadata_lines(
                window, feed.link, output_lines, add_blank=True)
            # draw feed description
            self._append_metadata_lines(
                window, "Description:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window,
                helpers.html_to_plain(feed.description) if
                helpers.is_true(Config["clean_html_descriptions"]) else
                feed.description, output_lines, add_blank=True)
            # draw feed copyright
            self._append_metadata_lines(
                window, "Copyright:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window, feed.copyright, output_lines, add_blank=True)
            # draw feed number of episodes
            num_dl = sum([episode.downloaded() for
                          episode in feed.episodes])
            self._append_metadata_lines(
                window, "Episodes:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window, "Found %d episodes (%d downloaded)" % (
                    len(feed.episodes), num_dl
                ), output_lines)
        elif episode is not None:
            # draw episode title
            self._append_metadata_lines(
                window, episode.title, output_lines, attr=curses.A_BOLD)
            # draw episode pubdate
            self._append_metadata_lines(
                window, episode.pubdate, output_lines, add_blank=True)
            # draw episode link
            self._append_metadata_lines(
                window, episode.link, output_lines, add_blank=True)
            # draw episode description
            self._append_metadata_lines(
                window, "Description:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window,
                helpers.html_to_plain(episode.description) if
                helpers.is_true(Config["clean_html_descriptions"]) else
                episode.description, output_lines, add_blank=True)
            # draw episode copyright
            self._append_metadata_lines(
                window, "Copyright:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window, episode.copyright, output_lines, add_blank=True)

            # draw episode downloaded
            self._append_metadata_lines(
                window, "Downloaded:", output_lines, attr=curses.A_BOLD)
            self._append_metadata_lines(
                window,
                "Episode downloaded and available for offline playback."
                if episode.downloaded() else "Episode not downloaded.",
                output_lines)

        y = 2
        for line in output_lines[:max_lines]:
            window.attrset(curses.color_pair(1))
            if line[0] != -1:
                window.attron(line[0])
            window.addstr(y, 0, line[1])
            y += 1 + line[1].count('\n')
Exemple #21
0
def test_is_true_yes():
    assert helpers.is_true('True')
    assert helpers.is_true('true')
    assert helpers.is_true('1')
Exemple #22
0
def test_is_true_no():
    assert not helpers.is_true("False")
    assert not helpers.is_true("")
    assert not helpers.is_true("hi")
Exemple #23
0
def test_is_true_yes():
    assert helpers.is_true("True")
    assert helpers.is_true("true")
    assert helpers.is_true("1")
Exemple #24
0
def test_is_true_no():
    assert not helpers.is_true('False')
    assert not helpers.is_true('')
    assert not helpers.is_true('hi')
Exemple #25
0
def main():
    database = Database()

    # parse command line arguments
    parser = argparse.ArgumentParser(prog=castero.__title__,
                                     description=castero.__description__)
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version='%(prog)s {}'.format(castero.__version__))
    parser.add_argument('--import', help='path to OPML file of feeds to add')
    parser.add_argument('--export', help='path to save feeds as OPML file')
    args = parser.parse_args()

    if vars(args)['import'] is not None:
        import_subscriptions(vars(args)['import'], database)
        sys.exit(0)
    elif vars(args)['export'] is not None:
        export_subscriptions(vars(args)['export'], database)
        sys.exit(0)

    # update fields in help menu text
    for field in Config:
        if "{%s}" % field in castero.__help__:
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s}" % field,
                    Config[field].ljust(11)
                )
        elif "{%s|" % field in castero.__help__:
            field2 = castero.__help__.split("{%s|" % field)[1].split("}")[0]
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s|%s}" % (field, field2),
                    ("%s or %s" % (Config[field], Config[field2])).ljust(11)
                )
        elif "{%s/" % field in castero.__help__:
            field2 = castero.__help__.split("{%s/" % field)[1].split("}")[0]
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s/%s}" % (field, field2),
                    ("%s/%s" % (Config[field], Config[field2])).ljust(11)
                )
    remaining_brace_fields = re.compile('\\{.*?\\}').findall(castero.__help__)
    for field in remaining_brace_fields:
        adjusted = field.replace("{", "").replace("}", "").ljust(11)
        castero.__help__ = \
            castero.__help__.replace(field, adjusted)

    # instantiate display
    redirect_stderr()
    stdscr = curses.initscr()
    display = Display(stdscr, database)
    display.clear()
    display.update_parent_dimensions()

    # check if we need to start reloading
    if helpers.is_true(Config['reload_on_start']):
        reload_thread = threading.Thread(target=database.reload,
                                         args=[display])
        reload_thread.start()

    # run initial display operations
    display.display_all()
    display._menus_valid = False
    display._update_timer = 0

    # core loop for the client
    running = True
    while running:
        display.display()
        char = display.getch()
        if char != -1:
            running = display.handle_input(char)

    sys.exit(0)
Exemple #26
0
def main():
    database = Database()

    # update fields in help menu text
    for field in Config:
        if "{%s}" % field in castero.__help__:
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s}" % field,
                    Config[field].ljust(9)
                )
        elif "{%s|" % field in castero.__help__:
            field2 = castero.__help__.split("{%s|" % field)[1].split("}")[0]
            castero.__help__ = \
                castero.__help__.replace(
                    "{%s|%s}" % (field, field2),
                    ("%s or %s" % (Config[field], Config[field2])).ljust(9)
                )
    remaining_brace_fields = re.compile('\{.*?\}').findall(castero.__help__)
    for field in remaining_brace_fields:
        adjusted = field.replace("{", "").replace("}", "").ljust(9)
        castero.__help__ = \
            castero.__help__.replace(field, adjusted)

    # check if user is running the client with an info flag
    info_flags = {
        'help': ['-h', '--help'],
        'version': ['-v', '--version']
    }
    if sys.argv[len(sys.argv) - 1] in info_flags['help']:
        print(castero.__help__)
        sys.exit(0)
    elif sys.argv[len(sys.argv) - 1] in info_flags['version']:
        print(castero.__version__)
        sys.exit(0)

    # instantiate the display object
    stdscr = curses.initscr()
    display = Display(stdscr, database)
    display.clear()
    display.update_parent_dimensions()

    # check if we need to start reloading
    if helpers.is_true(Config['reload_on_start']):
        reload_thread = threading.Thread(target=feeds.reload, args=[display])
        reload_thread.start()

    # run initial display operations
    display.display()
    display.update()
    display.refresh()

    # core loop for the client
    running = True
    while running:
        display.display()
        display.update()
        display.refresh()
        char = display.getch()
        if char != -1:
            running = display.handle_input(char)

    sys.exit(0)