Example #1
0
class Core(CorePluginBase):

    def __init__(self, name):
        """Used for tests only"""
        if name is not "test":
            super(Core, self).__init__(name)
        else:
            # To avoid warnings when running tests
            self._component_name = name

    def enable(self, config=None):
        self.log = yarss2.util.logger.Logger()
        self.torrent_handler = TorrentHandler(self.log)
        if config is None:
            self.yarss_config = YARSSConfig(self.log)
        else:
            self.yarss_config = config
        self.rssfeed_scheduler = RSSFeedScheduler(self.yarss_config, self.log)
        self.rssfeed_scheduler.enable_timers()
        self.log.info("Enabled YaRSS2 %s" % yarss2.util.common.get_version())

    def disable(self):
        self.yarss_config.save()
        self.rssfeed_scheduler.disable_timers()

    def update(self):
        pass

    @export
    def initiate_rssfeed_update(self, rssfeed_key, subscription_key=None):
        return self.rssfeed_scheduler.queue_rssfeed_update(rssfeed_key, subscription_key=subscription_key)

    @export
    def get_config(self):
        "Returns the config dictionary"
        return self.yarss_config.get_config()

    @export
    def save_email_configurations(self, email_configurations):
        conf = {"email_configurations": email_configurations}
        try:
            self.yarss_config.set_config(conf)
        except ValueError as (v):
            self.log.error("Failed to save email configurations:" + str(v))

    @export
    def save_subscription(self, dict_key=None, subscription_data=None, delete=False):
        """Saves the subscription in subscription_data.
        If subscription_data is None and delete=True, delete subscription with key==dict_key
        """
        if delete:
            if subscription_data is not None:
                self.log.warn("save_subscription called with delete=True, but rssfeed_data is not None!")
            else:
                self.log.info("Deleting Subscription '%s'" %
                         self.yarss_config.get_config()["subscriptions"][dict_key]["name"])
        try:
            return self.yarss_config.generic_save_config("subscriptions", dict_key=dict_key,
                                                         data_dict=subscription_data, delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save subscription:" + str(v))
        return None

    @export
    def save_rssfeed(self, dict_key=None, rssfeed_data=None, delete=False):
        """Saves the rssfeed in rssfeed_data.
        If rssfeed_data is None and delete=True, delete rssfeed with key==dict_key
        """
        try:
            if delete:
                if rssfeed_data is not None:
                    self.log.warn("save_rssfeed called with delete=True, but rssfeed_data is not None!")
                else:
                    self.log.info("Stopping and deleting RSS Feed '%s'" %
                             self.yarss_config.get_config()["rssfeeds"][dict_key]["name"])

            config = self.yarss_config.generic_save_config("rssfeeds", dict_key=dict_key,
                                                         data_dict=rssfeed_data, delete=delete)
            if delete is True:
                self.rssfeed_scheduler.delete_timer(dict_key)
            # Successfully saved rssfeed, check if timer was changed
            elif config:
                if self.rssfeed_scheduler.set_timer(rssfeed_data["key"], rssfeed_data["update_interval"]):
                    self.log.info("Scheduled RSS Feed '%s' with interval %s" %
                             (rssfeed_data["name"], rssfeed_data["update_interval"]))
            return config
        except ValueError as (v):
            self.log.error("Failed to save rssfeed:" + str(v))

    @export
    def save_cookie(self, dict_key=None, cookie_data=None, delete=False):
        """Save cookie to config.
        If cookie_data is None and delete=True, delete cookie with key==dict_key"""
        if cookie_data:
            if type(cookie_data["value"]) is not dict:
                self.log.error("Cookie value must be a dictionary!")
                return None
        try:
            return self.yarss_config.generic_save_config("cookies", dict_key=dict_key,
                                                         data_dict=cookie_data, delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save cookie:" + str(v))

    @export
    def save_email_message(self, dict_key=None, message_data=None, delete=False):
        """Save email message to config.
        If message_data is None, delete message with key==dict_key"""
        try:
            return self.yarss_config.generic_save_config("email_messages", dict_key=dict_key,
                                                         data_dict=message_data, delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save email message:" + str(v))

    @export
    def add_torrent(self, torrent_info):
        site_cookies_dict = get_matching_cookies_dict(self.yarss_config.get_config()["cookies"], torrent_info["link"])
        torrent_info["site_cookies_dict"] = site_cookies_dict
        torrent_download = self.torrent_handler.add_torrent(torrent_info)
        return torrent_download.to_dict()

    @export
    def get_path_completion(self, value):
        """
        Returns the available path completions for the input value.
        """
        return yarss2.util.common.get_path_completion(value)
Example #2
0
class RSSFeedSchedulerTestCase(unittest.TestCase):
    def setUp(self):  # NOQA
        self.rssfeeds = test_common.get_default_rssfeeds(5)
        self.rssfeeds["0"]["update_interval"] = 1
        self.rssfeeds["1"]["update_interval"] = 3
        self.rssfeeds["2"]["update_interval"] = 10
        self.rssfeeds["3"]["update_interval"] = 30
        self.rssfeeds["4"]["update_interval"] = 120

        self.config = test_common.get_test_config()
        self.config.set_config({
            "rssfeeds": self.rssfeeds,
            "email_configurations": {
                "send_email_on_torrent_events": False
            }
        })

        self.scheduler = RSSFeedScheduler(self.config, log)
        test_component = TestComponent()
        self.scheduler.torrent_handler.download_torrent_file = test_component.download_torrent_file
        self.scheduler.enable_timers()

    def tearDown(self):  # NOQA
        # Must stop loopingcalls or test fails
        self.scheduler.disable_timers()

    def test_enable_timers(self):
        # Now verify the timers
        for key in self.scheduler.rssfeed_timers.keys():
            # Is the timer running?
            self.assertTrue(
                self.scheduler.rssfeed_timers[key]["timer"].running)

            # Does the timer have the correct interval?
            interval = self.scheduler.rssfeed_timers[key]["timer"].interval
            self.assertEquals(self.rssfeeds[key]["update_interval"] * 60,
                              interval)
            self.assertEquals(
                self.rssfeeds[key]["update_interval"],
                self.scheduler.rssfeed_timers[key]["update_interval"])

    def test_disable_timers(self):
        self.scheduler.disable_timers()

        # Now verify that the timers have been stopped
        for key in self.scheduler.rssfeed_timers.keys():
            # Is the timer running?
            self.assertFalse(
                self.scheduler.rssfeed_timers[key]["timer"].running)

    def test_delete_timer(self):
        # Delete timer
        self.assertTrue(self.scheduler.delete_timer("0"))
        self.assertFalse(self.scheduler.delete_timer("-1"))

        self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 4)
        self.assertFalse("0" in self.scheduler.rssfeed_timers)

    def test_reschedule_timer(self):
        # Change interval to 60 minutes
        self.assertTrue(self.scheduler.set_timer("0", 60))

        interval = self.scheduler.rssfeed_timers["0"]["timer"].interval
        self.assertEquals(60 * 60, interval)
        self.assertEquals(
            self.scheduler.rssfeed_timers["0"]["update_interval"], 60)

    def test_schedule_timer(self):
        # Add new timer (with key "5") with interval 60 minutes
        self.assertTrue(self.scheduler.set_timer("5", 60))

        # Verify timer values
        interval = self.scheduler.rssfeed_timers["5"]["timer"].interval
        self.assertEquals(60 * 60, interval)
        self.assertEquals(
            self.scheduler.rssfeed_timers["5"]["update_interval"], 60)

        # Should now be 6 timers
        self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 6)

    def test_rssfeed_update_handler(self):
        subscription = yarss2.yarss_config.get_fresh_subscription_config(
            rssfeed_key="0", key="0")
        self.config.set_config({"subscriptions": {"0": subscription}})

        # Check that last_update changes
        old_last_update = self.rssfeeds["0"]["last_update"]

        # Run the rssfeed with key 0
        self.scheduler.rssfeed_update_handler("0")
        self.assertNotEquals(old_last_update,
                             self.rssfeeds["0"]["last_update"])

        old_last_update = self.rssfeeds["0"]["last_update"]

        # Run the subscription with key 0 like when the user runs it manually
        self.scheduler.rssfeed_update_handler(None, "0")

        # last_update should not have changed
        self.assertEquals(old_last_update, self.rssfeeds["0"]["last_update"])

    def test_rssfeed_update_handler_exception(self):
        subscription = yarss2.yarss_config.get_fresh_subscription_config(
            rssfeed_key="0", key="0")
        self.config.set_config({"subscriptions": {"0": subscription}})

        self.scheduler.rssfeed_update_handler_safe("0")
        # Run the rssfeed with invalid key
        self.assertRaises(KeyError, self.scheduler.rssfeed_update_handler, 1)
        # Safe function should not raise exception
        self.assertFalse(self.scheduler.rssfeed_update_handler_safe(1))

    def test_ttl_value_updated(self):
        config = test_common.get_test_config_dict()
        config["rssfeeds"]["0"]["update_interval"] = 30
        config["rssfeeds"]["0"]["obey_ttl"] = True
        config["rssfeeds"]["0"]["url"] = yarss2.util.common.get_resource(
            test_common.testdata_rssfeed_filename, path="tests")

        yarss_config = test_common.get_test_config()
        yarss_config.set_config(config)

        self.scheduler.disable_timers()
        self.scheduler.yarss_config = yarss_config
        self.scheduler.enable_timers()

        def add_torrents_pass(*arg):
            pass

        self.scheduler.add_torrents_func = add_torrents_pass

        # Run the rssfeed with key 0
        self.scheduler.rssfeed_update_handler("0")

        # Verify that update_interval of rssfeed in config was updated
        self.assertEquals(
            yarss_config.get_config()["rssfeeds"]["0"]["update_interval"], 60)

        # Verify that update_interval of the timer was updated
        self.assertEquals(
            self.scheduler.rssfeed_timers["0"]["update_interval"], 60)
        self.scheduler.disable_timers()

    def test_rssfeed_update_queue(self):
        """Tests that the add_torrents_func is called the correct number of times,
        and that add_torrents_func is running in the main thread.
        """
        # Don't use the loopingcall, so disable just to avoid any trouble
        self.scheduler.disable_timers()
        self.config.set_config(test_common.get_test_config_dict())

        add_torrents_count = []
        main_thread = threading.current_thread()

        def add_torrents_cb(*arg):
            self.assertEquals(
                main_thread, threading.current_thread(),
                "add_torrents must be called from the main thread!")
            add_torrents_count.append(0)

        self.scheduler.add_torrents_func = add_torrents_cb

        d_first = self.scheduler.queue_rssfeed_update(rssfeed_key="0")
        self.scheduler.queue_rssfeed_update(subscription_key="1")
        self.scheduler.queue_rssfeed_update(rssfeed_key="1")
        d_last = self.scheduler.queue_rssfeed_update(rssfeed_key="2")

        def verify_callback_count(args):
            self.assertEquals(len(add_torrents_count), 3)

        return DeferredList([d_first, d_last]).addBoth(verify_callback_count)
Example #3
0
class Core(CorePluginBase):
    def __init__(self, name):
        """Used for tests only"""
        if name is not "test":
            super(Core, self).__init__(name)
        else:
            # To avoid warnings when running tests
            self._component_name = name

    def enable(self, config=None):
        self.log = yarss2.util.logger.Logger()
        self.torrent_handler = TorrentHandler(self.log)
        if config is None:
            self.yarss_config = YARSSConfig(self.log)
        else:
            self.yarss_config = config
        self.rssfeed_scheduler = RSSFeedScheduler(self.yarss_config, self.log)
        self.rssfeed_scheduler.enable_timers()
        self.log.info("Enabled YaRSS2 %s" % yarss2.util.common.get_version())

    def disable(self):
        self.yarss_config.save()
        self.rssfeed_scheduler.disable_timers()

    def update(self):
        pass

    @export
    def initiate_rssfeed_update(self, rssfeed_key, subscription_key=None):
        return self.rssfeed_scheduler.queue_rssfeed_update(
            rssfeed_key, subscription_key=subscription_key)

    @export
    def get_config(self):
        "Returns the config dictionary"
        return self.yarss_config.get_config()

    @export
    def save_general_config(self, conf):
        conf = {"general": conf}
        try:
            self.yarss_config.set_config(conf)
        except ValueError as (v):
            self.log.error("Failed to save general configurations:" + str(v))

    @export
    def save_email_configurations(self, email_configurations):
        conf = {"email_configurations": email_configurations}
        try:
            self.yarss_config.set_config(conf)
        except ValueError as (v):
            self.log.error("Failed to save email configurations:" + str(v))

    @export
    def save_subscription(self,
                          dict_key=None,
                          subscription_data=None,
                          delete=False):
        """Saves the subscription in subscription_data.
        If subscription_data is None and delete=True, delete subscription with key==dict_key
        """
        if delete:
            if subscription_data is not None:
                self.log.warn(
                    "save_subscription called with delete=True, but rssfeed_data is not None!"
                )
            else:
                self.log.info("Deleting Subscription '%s'" %
                              self.yarss_config.get_config()["subscriptions"]
                              [dict_key]["name"])
        try:
            return self.yarss_config.generic_save_config(
                "subscriptions",
                dict_key=dict_key,
                data_dict=subscription_data,
                delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save subscription:" + str(v))
        return None

    @export
    def save_rssfeed(self, dict_key=None, rssfeed_data=None, delete=False):
        """Saves the rssfeed in rssfeed_data.
        If rssfeed_data is None and delete=True, delete rssfeed with key==dict_key
        """
        try:
            if delete:
                if rssfeed_data is not None:
                    self.log.warn(
                        "save_rssfeed called with delete=True, but rssfeed_data is not None!"
                    )
                else:
                    self.log.info("Stopping and deleting RSS Feed '%s'" %
                                  self.yarss_config.get_config()["rssfeeds"]
                                  [dict_key]["name"])

            config = self.yarss_config.generic_save_config(
                "rssfeeds",
                dict_key=dict_key,
                data_dict=rssfeed_data,
                delete=delete)
            if delete is True:
                self.rssfeed_scheduler.delete_timer(dict_key)
            # Successfully saved rssfeed, check if timer was changed
            elif config:
                if self.rssfeed_scheduler.set_timer(
                        rssfeed_data["key"], rssfeed_data["update_interval"],
                        rssfeed_data["update_on_startup"]):
                    self.log.info("Scheduled RSS Feed '%s' with interval %s" %
                                  (rssfeed_data["name"],
                                   rssfeed_data["update_interval"]))
            return config
        except ValueError as (v):
            self.log.error("Failed to save rssfeed:" + str(v))

    @export
    def save_cookie(self, dict_key=None, cookie_data=None, delete=False):
        """Save cookie to config.
        If cookie_data is None and delete=True, delete cookie with key==dict_key"""
        if cookie_data:
            if type(cookie_data["value"]) is not dict:
                self.log.error("Cookie value must be a dictionary!")
                return None
        try:
            return self.yarss_config.generic_save_config("cookies",
                                                         dict_key=dict_key,
                                                         data_dict=cookie_data,
                                                         delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save cookie:" + str(v))

    @export
    def save_email_message(self,
                           dict_key=None,
                           message_data=None,
                           delete=False):
        """Save email message to config.
        If message_data is None, delete message with key==dict_key"""
        try:
            return self.yarss_config.generic_save_config(
                "email_messages",
                dict_key=dict_key,
                data_dict=message_data,
                delete=delete)
        except ValueError as (v):
            self.log.error("Failed to save email message:" + str(v))

    @export
    def send_test_email(self, email_key):
        """
        Send a test email
        """
        self.email_config = self.yarss_config.get_config().get(
            'email_configurations', {})
        self.email_messages = self.yarss_config.get_config().get(
            'email_messages', {})
        torrents = ["Torrent title"]
        return send_torrent_email(
            self.email_config,
            self.email_messages[email_key],
            subscription_data={"name": "Test subscription"},
            torrent_name_list=torrents,
            deferred=True)

    @export
    def add_torrent(self, torrent_info):
        site_cookies_dict = get_matching_cookies_dict(
            self.yarss_config.get_config()["cookies"], torrent_info["link"])
        torrent_info["site_cookies_dict"] = site_cookies_dict
        if "rssfeed_key" in torrent_info:
            rssfeed_data = self.yarss_config.get_config()["rssfeeds"][
                torrent_info["rssfeed_key"]]
            torrent_info["user_agent"] = get_user_agent(
                rssfeed_data=rssfeed_data)
        torrent_download = self.torrent_handler.add_torrent(torrent_info)
        return torrent_download.to_dict()

    @export
    def get_completion_paths(self, value):
        """
        Returns the available path completions for the input value.
        """
        return yarss2.util.common.get_completion_paths(value)
class RSSFeedSchedulerTestCase(unittest.TestCase):

    def setUp(self):
        self.rssfeeds = common.get_default_rssfeeds(5)
        self.rssfeeds["0"]["update_interval"] = 1
        self.rssfeeds["1"]["update_interval"] = 3
        self.rssfeeds["2"]["update_interval"] = 10
        self.rssfeeds["3"]["update_interval"] = 30
        self.rssfeeds["4"]["update_interval"] = 120

        self.config = common.get_test_config()
        self.config.set_config({"rssfeeds": self.rssfeeds, "email_configurations": {"send_email_on_torrent_events": False} })

        self.scheduler = RSSFeedScheduler(self.config, log)
        test_component = TestComponent()
        self.scheduler.torrent_handler.download_torrent_file = test_component.download_torrent_file
        self.scheduler.enable_timers()

    def tearDown(self):
        # Must stop loopingcalls or test fails
        self.scheduler.disable_timers()

    def test_enable_timers(self):
        # Now verify the timers
        for key in self.scheduler.rssfeed_timers.keys():
            # Is the timer running?
            self.assertTrue(self.scheduler.rssfeed_timers[key]["timer"].running)

            # Does the timer have the correct interval?
            interval = self.scheduler.rssfeed_timers[key]["timer"].interval
            self.assertEquals(self.rssfeeds[key]["update_interval"] * 60, interval)
            self.assertEquals(self.rssfeeds[key]["update_interval"], self.scheduler.rssfeed_timers[key]["update_interval"])

    def test_disable_timers(self):
        self.scheduler.disable_timers()

        # Now verify that the timers have been stopped
        for key in self.scheduler.rssfeed_timers.keys():
            # Is the timer running?
            self.assertFalse(self.scheduler.rssfeed_timers[key]["timer"].running)

    def test_delete_timer(self):
        # Delete timer
        self.assertTrue(self.scheduler.delete_timer("0"))
        self.assertFalse(self.scheduler.delete_timer("-1"))

        self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 4)
        self.assertFalse(self.scheduler.rssfeed_timers.has_key("0"))

    def test_reschedule_timer(self):
        # Change interval to 60 minutes
        self.assertTrue(self.scheduler.set_timer("0", 60))

        interval = self.scheduler.rssfeed_timers["0"]["timer"].interval
        self.assertEquals(60 * 60, interval)
        self.assertEquals(self.scheduler.rssfeed_timers["0"]["update_interval"], 60)

    def test_schedule_timer(self):
        # Add new timer (with key "5") with interval 60 minutes
        self.assertTrue(self.scheduler.set_timer("5", 60))

        # Verify timer values
        interval = self.scheduler.rssfeed_timers["5"]["timer"].interval
        self.assertEquals(60 * 60, interval)
        self.assertEquals(self.scheduler.rssfeed_timers["5"]["update_interval"], 60)

        # Should now be 6 timers
        self.assertEquals(len(self.scheduler.rssfeed_timers.keys()), 6)

    def test_rssfeed_update_handler(self):
        subscription = yarss2.yarss_config.get_fresh_subscription_config(rssfeed_key="0", key="0")
        self.config.set_config({"subscriptions": {"0": subscription} })

        # Check that last_update changes
        old_last_update = self.rssfeeds["0"]["last_update"]

        # Run the rssfeed with key 0
        self.scheduler.rssfeed_update_handler("0")
        self.assertNotEquals(old_last_update, self.rssfeeds["0"]["last_update"])

        old_last_update = self.rssfeeds["0"]["last_update"]

        # Run the subscription with key 0 like when the user runs it manually
        self.scheduler.rssfeed_update_handler(None, "0")

        # last_update should not have changed
        self.assertEquals(old_last_update, self.rssfeeds["0"]["last_update"])

    def test_rssfeed_update_handler_exception(self):
        subscription = yarss2.yarss_config.get_fresh_subscription_config(rssfeed_key="0", key="0")
        self.config.set_config({"subscriptions": {"0": subscription} })

        # Check that last_update changes
        old_last_update = self.rssfeeds["0"]["last_update"]

        # Run the rssfeed with invalid key
        ret = self.scheduler.rssfeed_update_handler_safe("0")
        self.scheduler.rssfeed_update_handler_safe("0")
        self.assertFalse(self.scheduler.rssfeed_update_handler_safe(1))
        self.assertRaises(KeyError, self.scheduler.rssfeed_update_handler, 1)

    def test_ttl_value_updated(self):
        config = common.get_test_config_dict()
        config["rssfeeds"]["0"]["update_interval"] = 30
        config["rssfeeds"]["0"]["obey_ttl"] = True
        config["rssfeeds"]["0"]["url"] = yarss2.util.common.get_resource(common.testdata_rssfeed_filename, path="tests")

        yarss_config = common.get_test_config()
        yarss_config.set_config(config)

        self.scheduler.disable_timers()
        self.scheduler.yarss_config = yarss_config
        self.scheduler.enable_timers()

        def add_torrents_pass(*arg):
            pass
        self.scheduler.add_torrent_func = add_torrents_pass

        # Run the rssfeed with key 0
        self.scheduler.rssfeed_update_handler("0")

        # Verify that update_interval of rssfeed in config was updated
        self.assertEquals(yarss_config.get_config()["rssfeeds"]["0"]["update_interval"], 60)

        # Verify that update_interval of the timer was updated
        self.assertEquals(self.scheduler.rssfeed_timers["0"]["update_interval"], 60)
        self.scheduler.disable_timers()

    def test_rssfeed_update_queue(self):
        """Tests that the add_torrent_func is called the correct number of times,
        and that add_torrent_func is running in the main thread.
        """
        # Don't use the loopingcall, so disable just to avoid any trouble
        self.scheduler.disable_timers()
        self.config.set_config(common.get_test_config_dict())

        add_torrents_count = []
        main_thread = threading.current_thread()

        def add_torrents_cb(*arg):
            self.assertEquals(main_thread, threading.current_thread(), "add_torrents must be called from the main thread!")
            add_torrents_count.append(0)
        self.scheduler.add_torrent_func = add_torrents_cb

        d_first = self.scheduler.queue_rssfeed_update(rssfeed_key="0")
        self.scheduler.queue_rssfeed_update(subscription_key="1")
        self.scheduler.queue_rssfeed_update(rssfeed_key="1")
        d_last = self.scheduler.queue_rssfeed_update(rssfeed_key="2")

        def verify_callback_count(args):
            self.assertEquals(len(add_torrents_count), 3)

        d_last.addCallback(verify_callback_count)
        return d_last