<commit_before>import logging
from datetime import datetime
from queue import Queue, Empty

import libtorrent as lt

from tveebot_tracker.episode import Episode, EpisodeFile, State
from tveebot_tracker.episode_db import EpisodeDB, connect
from tveebot_tracker.stoppable_thread import StoppableThread

logger = logging.getLogger('downloader')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)


class Downloader(StoppableThread):
    """
    The downloader is the component responsible for actually downloading
    the episode files. It is a simple torrent client.

    This is an abstract base class for downloader implementations. It
    implements the logic of having the downloader run in loop and queue
    episodes to be downloaded. The actual steps/protocol are left to the be
    implemented by the subclasses.
    """

    QUEUE_TIMEOUT = 5.0  # seconds

    state_str = ['queued', 'checking', 'downloading metadata',
                 'downloading', 'finished', 'seeding', 'allocating']

    def __init__(self, database: EpisodeDB, config, queue: Queue = Queue()):
        super().__init__()
        self._database = database
        self.download_dir = config.download_dir

        # This queue is shared with the tracker. The tracker 'produces'
        # episodes to download. The Downloader consumes those episodes and
        # downloads them.
        self._queue = queue

        # noinspection PyArgumentList
        self.session = lt.session()
        self.session.listen_on(6881, 6891)

        self._handles = []  # holds episode, file, and handle

    @property
    def queue(self):
        """ Download queue, including the episodes to be downloaded """
        return self._queue

    def run(self):
        # TODO restart downloads for episodes ser as DOWNLOADING

        while not self.stopped():
            logger.debug("looking for finished downloads")
            finished = []
            for episode, file, handle in self._handles:
                if handle.status().is_seeding:
                    finished.append((episode, file, handle))
                    logger.debug(f"found finished download: {episode}")

            # Remove handles corresponding to finished downloads
            for episode, file, handle in finished:
                logger.info(f"finished downloading {episode}")
                self._download_finished(episode, file)
                self.session.remove_torrent(handle)
                self._handles.remove((episode, file, handle))

            try:
                episode, file = self.queue.get(timeout=self.QUEUE_TIMEOUT)
                self.download(episode, file)<commit_msg>Have Downloader take advantage of the Config abstraction<commit_after>import logging
from datetime import datetime
from queue import Queue, Empty

import libtorrent as lt

from tveebot_tracker.config import Config
from tveebot_tracker.episode import Episode, EpisodeFile, State
from tveebot_tracker.episode_db import EpisodeDB, connect
from tveebot_tracker.stoppable_thread import StoppableThread

logger = logging.getLogger('downloader')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)


class Downloader(StoppableThread):
    """
    The downloader is the component responsible for actually downloading
    the episode files. It is a simple torrent client.

    This is an abstract base class for downloader implementations. It
    implements the logic of having the downloader run in loop and queue
    episodes to be downloaded. The actual steps/protocol are left to the be
    implemented by the subclasses.
    """

    QUEUE_TIMEOUT = 5.0  # seconds

    state_str = ['queued', 'checking', 'downloading metadata',
                 'downloading', 'finished', 'seeding', 'allocating']

    def __init__(self, database: EpisodeDB, config: Config,
                 queue: Queue = Queue()):
        super().__init__()
        self._database = database
        self._config = config

        # This queue is shared with the tracker. The tracker 'produces'
        # episodes to download. The Downloader consumes those episodes and
        # downloads them.
        self._queue = queue

        # noinspection PyArgumentList
        self.session = lt.session()
        self.session.listen_on(6881, 6891)

        self._handles = []  # holds episode, file, and handle

    @property
    def download_dir(self):
        """ Download queue, including the episodes to be downloaded """
        return self._config.download_dir

    @property
    def queue(self):
        """ Download queue, including the episodes to be downloaded """
        return self._queue

    def run(self):
        # TODO restart downloads for episodes ser as DOWNLOADING

        while not self.stopped():
            logger.debug("looking for finished downloads")
            finished = []
            for episode, file, handle in self._handles:
                if handle.status().is_seeding:
                    finished.append((episode, file, handle))
                    logger.debug(f"found finished download: {episode}")

            # Remove handles corresponding to finished downloads
            for episode, file, handle in finished:
                logger.info(f"finished downloading {episode}")
                self._download_finished(episode, file)
                self.session.remove_torrent(handle)
                self._handles.remove((episode, file, handle))

            try:
                episode, file = self.queue.get(timeout=self.QUEUE_TIMEOUT)
                self.download(episode, file)
{'fraction_non_alphanumeric': 0.07714388231072838, 'fraction_numerical': 0.003588087549336204, 'mean_word_length': 2.634289439374185, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 57, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4202433', 'n_tokens_mistral': 1484, 'n_tokens_neox': 1388, 'n_words': 474}