RSS Feed Readers Part IV - Filter Tools

29 Nov 2017 . Category: Dev

I’ve wrote a very basic filter for FreshRSS. It simply allows me to specify filters for individual feeds using a json file as follows:

    "filters":[	"druckenmiller" ,"tudor" ,"krieger" ,"collum" ,"kolanovic" ,"horseman" ]
    "filters":["est of" , "comedian", "UFC", "fight", "MMA"]
    "filters":["see the data"]

The json file is user specific, so each user can define their own filters. Which is nice.

It has two modes of operation. If the ‘default’ parameter is set to ‘hide’, then the words in the ‘filters’ section will unhide an article if they appear in the title or content. If the Default is set to ‘show’, then the defined words will hide an article. It’s pretty basic, but works well for my needs.

I’ve checked the code in over at github in a new RssTools repository. It’s the first code I’ve wrote in PHP for years so could be all wrong, but here’s what it looks like anyway:

// Performs a very simple filtering operation on rss feeds.
// configuration is stored in per user config filter, see example file for details.
// Setting 'default' to 'show' shows all articles EXCEPT if the defines words appear in article
// Setting 'default' to 'hide' hides all articles EXCEPT if the defines words appear in article
class SimpleArticleFilterExtension extends Minz_Extension {
  public function init() {
    $this->registerHook('entry_before_insert', array($this, 'checkForStrings'));

    // Was using this one for debug.  Doesn't store in Db.  
    // It leaves the count unmodified - nice to see how many skipped.... 
    //$this->registerHook('entry_before_display', array($this, 'checkForStrings'));

  public function checkForStrings($entry) {
    // $entry is FreshRSS_Entry object
    // Accessible fields:
    // title, author, content, link, date, is_read, is_favourite, feed

    // Get json settings filename
    // Each user can have their own json file: "DefinedFilters.User.json"
    $current_user = Minz_Session::param('currentUser');
    $filename =  'DefinedFilters.'.$current_user.'.json';
    $filepath = join_path($this->getPath(), $filename);

    // Read the json file
    $jsonString = file_get_contents($filepath);
    $filterSettings = json_decode($jsonString);

    // Get the site settings if defined for this site
    $filterExists = false;
    foreach($filterSettings as $filterEntry)
      // Unable to use the url as some rss feeds don't have it or are shared across many feeds ie twitter
      // Instead use feed id which is unique, which can be read from url eg f_8
      if (strpos($entry->feed(), $filterEntry->feedId) !== false)
        $filterExists = true;

        $site = $filterEntry->site;
        $default = $filterEntry->default;
        $filters = $filterEntry->filters;

    //Got a filter, so do the processing
      // Combine title and content, so only doing one search
      $titlePlusContent = $entry->content().$entry->title(); 

      // Are any of our keywords in the title or body
      $filterMatch = false;
      foreach( $filters as $filter)
        //Check. Case insensitive
        if ( stripos($titlePlusContent, $filter) !== false)
          // Got a defined word.  NO need to keep checking
          $filterMatch = true;

      // Test for the scenarios where we wish to hide entry:
      // i)  Where default is to hide, and we didn't find one of the filters
      // ii) Where teh default action is to show, but we found one of our filters
      if(($default==="hide" && !$filterMatch) || ($default==="show" && $filterMatch))
        // Don't return entry.  Has effect of hiding.
        // poss could set is_read, but doesn't work for entry_before_display hook

    // We want to see this one!
    return $entry;

  }// End checkForStrings
}//End Class


Iain Benson is a real person and not a grassy plant viking. He lives in Scotland. In his spare time, Iain likes tinkering with his Raspberry Pi, going for long walks and drinking wine. Preferably all at the same time.