Possibility to run (selected) filters manually

Wiki says: “It is suggested to only rely on filters applying to articles imported after the filter had been created - they will not retroactively apply to your article database.”

This makes perfect sense, but it would still be nice to be able to run specific filters manually to the database. I have tens of thousands of articles and I just created some non-trivial filters. It would be nice to be able to do an initial run of those filters.

1 Like

Understandable. But if you really want to apply filters to existing articles in the database you can just run some PHP script to do that. If you already have the code in the plugin to do it for new articles coming in, you could just take that code and create a one-time use script to apply it to the database.

Take a look at the cache_starred_images plugin. It runs during the maintenance routine to update existing articles in the database. It might give you some ideas for re-factoring your code.

If the changes to the articles are not too important or CPU intensive, you can just store the original article in the database (as would normally happen) and use one of the hooks available to filter the article content in real-time as it’s being served to the TT-RSS user.

Thanks for the response!

I really wouldn’t want to write custom PHP scripts… First, I would need to learn PHP and a bit of how the whole TTRSS system works (database etc). Second, I might not have such permissions in the first place. I’m just a user in TTRSS, I don’t have any CLI access to the server, I only have access to the TTRSS web site. Third, writing such scripts is really error-prone and might corrupt the whole database (so I would need to learn to backup the whole database too). Fourth, the solution would not help anyone else or at least wouldn’t be easily usable for them.

FWIW, Thunderbird is one example that has the possibility to run filters manually.

Once I have defined new filters, I think it’s a quite common usecase that one wants to run the filter for the already fetched articles in the database. For instance, adding labels to articles or marking some of them read. I don’t see any problems in this feature as such, just of course some work would be needed to implement it. Do you see any problems or reasons not to include this kind of feature?

Anyway, the filter tool is amazing, because one can create really powerful filters by combining regex rules. I tried it and fell in love immediately.

1 Like

well, feel free to file a PR.

… oh

Yes, thanks, I do feel free to file a PR. Probably it would be too much an effort for me to get familiar with PHP and TTRSS to do that but we’ll see. Anyway, I wanted to suggest this feature because I thought it’d be a really useful feature and it’d make TTRSS even better but feel free to ignore. I’m not asking anyone to do anything, just sharing a feature idea.

EDIT: But I would obviously be super happy and extremely thankful if anyone made the effort of implementing this. :smile: :heart:

Hmm, I might have a look on this during the weekend, if I have some time. If I understood correctly, this feature would be something that you would approve (based on the encouragement to submit a PR)? Just checking I won’t waste my time. Do you have any pointers on where to find relevant piece of code and which parts need modifying and what to take into account or any other helpful comments? I found that classes/pref/filters.php contains the filter preferences, so it seems quite straightforward to add something like “Run selected filters” button. But I couldn’t find where are relevant functions for applying filters to articles. Quite likely I need to spend quite a bit of time understanding the codebase and learning PHP, so I might not get anything done. But we’ll see if I find the time to at least try.

i would suggest making a separate filter-runner plugin and posting it in the T&P subforum.

this way you also get to do all the fun stuff, i.e. continued maintenance.

you might be a bit too optimistic.

My optimism was referring only to the minor step of adding the button, not implementing the actual running of the filters. :slight_smile: For the actual filtering stuff, I was a bit lost and asked for some pointers. But I’m not probably interested in implementing this as a plugin and maintaining it, so I think I’ll not try to implement it then. Maybe I’ll write my own custom PHP script then instead. I would love to see this feature as a part of TT-RSS though. Thanks for the feedback anyway.

I took a peek here and it indeed looks like it would take some effort; especially on the UI side so users don’t shoot themselves in the foot. RSSUtils::get_article_filters is doing the heavy lifting of determining if an article matches a particular list of filters and returns the resulting actions that should be performed.

It’s safe enough for testFilterDo to check for matches but when it comes to applying the filter actions you can possibly do a lot of clobbering if you select only a subset of rules.

There’s a lot of opportunity to do something that would result in a support request post.

If your ultimate goal is the same as mine: to apply some filters according to more complex rules like multiple regular expressions then there might be an alternative with less risk: something akin to “advanced search” plugin that let’s you make changes as you would on the main UI.

It might be possible to use RSSUtils::get_article_filters to perform the “advanced search” which would give it the same filtering power but still leave the user in charge of applying the changes they want to make on the selected articles.

1 Like

Given the complexity of queryFeedHeadlines it looks like it’ll have to be a trade-off between allowing for the built-in UI filters to apply and allowing for queries against multiple feeds at once; making a version of queryFeedHeadlines that supports multiple feeds seems like it would be massively error prone.

Using a query like the one used in testFilterDo would be handy but if I understand correctly direct database queries are not exposed to plugins so that would mean a core change would be needed to provide a plugin helper.

Finally, I was only able to find 2 alternatives to creating the filter object: provide a feed and query all filters for that feed (conflicting filters will cause problems so that’s not viable outside of a hacky demo) or collect the parameters from the again similar to how testFilterDo uses the form data to construct a filter on the fly.

I hacked on the vfeed example as an experiment; using the anonymous class to wrap fetch() is a bit brittle, does anyone know a better way to filter on a result cursor?

Also apologies if I used any PHP anti-patterns; I can count on one hand the number of times I’ve had to touch PHP code.

<?php
class VF_Filters extends Plugin {

	private $host;
	private $dummy_id;

	function about() {
		return array(0.1,
			"Filter vfeed plugin",
			"Tyler Szabo");
	}

	function init($host) {
		$this->host = $host;

		$this->dummy_id = $host->add_feed(-1, 'Dummy feed', 'images/pub_set.svg', $this);
	}

	function get_unread($feed_id) {
		return null;
	}

	function get_headlines($feed_id, $options) {

		$feed = 3; # HACKHACK hardcoded for local testing - need to get this from user

		$owner_uid = $this->host->get_owner_uid();

		$filters = RSSUtils::load_filters($feed, $owner_uid); # HACKHACK - should get the filter from the user

		$params = array(
			"feed" => $feed,
			"limit" => $options["limit"],
			"view_mode" => $options['view_mode'],
			"search" => $options['search'],
			"override_order" => $options['override_order'],
			"offset" => $options["offset"],
			"filter" => $options["filter"],
			"since_id" => $options["since_id"],
			"include_children" => $options["include_children"]
		);
		$qfh_ret = Feeds::queryFeedHeadlines($params);

		$qfh_ret[0] = new class($qfh_ret[0], $filters) {
			private $res;
			private $filters;
			public function __construct($res, $filters) {
				$this->res = $res;
				$this->filters = $filters;
			}
			public function fetch() {
				while ($article = $this->res->fetch()) {
					$filter_actions = RSSUtils::get_article_filters($this->filters, $article['title'], $article['content'], $article['link'], $article['author'], explode(",", $article['tag_cache']));
					if (count($filter_actions) > 0) {
						return $article;
					}
				}

				return $article;
			}
		};

		$qfh_ret[1] = __("Filtered: " . $qfh_ret[1]);

		return $qfh_ret; #array($res, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id, $vfeed_query_part != "", $query_error_override);
	}

	function api_version() {
		return 2;
	}

}
?>
1 Like