Redirect multi-page news articles to a single page view using Greasemonkey

A lot of news websites split their articles into multiple pages. In theory this drives page impressions and thus ad revenue. In practice it is just annoying. The Greasemonkey script below automagically redirects you to a news article’s full page (in this case on zeit.de). It uses a MutiationObserver to wait for the pager UI element. The script kicks in once it appears – no need to wait until their page (or ads?!) have been fully loaded. 🙂

You can easily modify it:

1. Include all pages that might contain a multi-page article
2. Exclude all pages that might lead to a loop (especially the target site) or that will not contain a pager element (MutiationObserver can easily add a couple of milliseconds of loading time on complex pages)
3. Change the class name of the pager element to the one used by your site
4. Change the target location to the one you want to be redirect to

// ==UserScript==
// @name         Zeit Onepager
// @namespace    kubath.com
// @version      1.0
// @description  Zeigt mehrseitige Zeit-Artikel auf einer Seite
// @author       Florian Kubath
// @match        *://www.zeit.de/*
// @exclude      *://www.zeit.de/*/komplettansicht
// @grant        none
// @run-at       document-start
// ==/UserScript==

var mutationObserver;

window.addEventListener('load', function() {
  
  mutationObserver.disconnect();
}, false);

(function onepager() {

    mutationObserver = new MutationObserver(function (mutations) {

        var pager = document.getElementsByClassName('article-pager__all'); // Change to your site's pager element's class name
        if (pager.length > 0) {

            window.location.replace(window.location.href + '/komplettansicht'); // Change to your target site's URL 
            mutationObserver.disconnect();
            return;
        }
    });

    mutationObserver.observe(document, {

        childList: true,
        subtree: true
    });
}());

 

Ready-to-install scripts for:

golem.de
heise.de
zeit.de

Stepscout: A tool to search for jobs and apartments at the same time

I think living near one’s workplace is a great benefit for a good work-live balance. If you are living in your current city for a while, you probably already know where the best places to live and work are. But if you are starting to search for one or the other, you might ask yourself which neighborhood is the best to reduce the daily commute to a minimum. To find answers to this question I build Stepscout. It leverages the Stepstone and ImmobilienScout24 API’s to find jobs & apartments in one go and marks them together on a Google Map. This visualization helps to find job clusters, apartment clusters or ideally job-apartment-clusters.

The trick in this project was to make use of Google’s Places API to search for latitude and longitude of every company in the Stepstone result response. Even though Stepstone’s response JSON contains fields for geographic coordinates, they are empty or filled with generic values for the most part.

If you are living in Germany, you can check out the tool here or get a first impression below.

Disable autoplay on Youtube’s new 2017 material design release

I happened to receive Youtube’s new 2017 desktop material design when I was watching videos the other day. All in all a great redesign which closes the gap to their other channels. You can force the new design by running the command below in your Firefox’s console’s command line (press [CMD] + [SHIFT] + [K]). Reload the page when done.

document.cookie="PREF=f6=4;path=/;domain=.youtube.com";

Unfortunately, the Firefox Greasemonkey script I used to disable Youtube’s autoplay feature does not work with their new site. Just removing the autoplay toggle’s node from the DOM does not do the trick anymore. My investigations brought to light that the f5 property of the PREF cookie is used to toggle the autoplay feature under the hood. f5=30000 is the default value to disable autoplay and f5=20000 the default to enable it. So I built a new Greasemonkey script which reads the existing PREF cookie, looks for the f5-property and sets it accordingly (or adds it if not present). At the same time all existing values are preserved. Additionally, the autonav_disable cookie is set. It was the first thing I found during my investigations which made me think “easy….”. Anyways, it turned out this cookie is not used to control autoplay. Not sure what it does, but I set it just to play safe. Finally a MutationObserver is used to wait for the autoplay toggle and remove it once it is loaded. DOMContentLoaded did not help as it seems like the node is added afterwards. To install the script, first get Greasemonkey for Firefox here . Once Greasemonkey is installed, click here to install the Userscript or paste the code below into your own script. Force reload Youtube by pressing [CMD] + [F5] after successfully installing the script.

// ==UserScript==
// @name        Disable Youtube Autoplay Material Design
// @namespace   https://kubath.com
// @include     *youtube.com/*
// @version     1
// @grant       none
// @run-at      document-start
// ==/UserScript==

/*
 * This script disables Youtube's autoplay feature on the new 2017 material design page. 
 * The new design is currently in test and will not be shown to every user. 
 * To enforce Youtube's new material design run the command below in the console and reload the page.
 * document.cookie="PREF=f6=4;path=/;domain=.youtube.com";
 * 
 * This script will also disable autoplay on Youtube's previous page (prior to 2017).
 *
 * Bonus: To hide the cookie consent header uncomment setCookieConsentHideCookie(); below.
*/


var cookieDomainValue = '.youtube.com';
var prefCookieKey = 'PREF';
var prefCookieAutoplayToggleKey = 'f5';
var prefCookieAutoplayToggleValueAutonavDisabled = 30000;


setAutonavDisabledCookie(); // set autonav_disable cookie
setAutonavDisabledPrefCookie(); // set autoplay pref cookie (f5 = 30000)
// setCookieConsentHideCookie(); // uncomment to hide cookie consent bar
removeAutonavElement(); // remove autoplay element


// get cookies
function getCookie(name) {
  var value = '; ' + document.cookie;
  var parts = value.split('; ' + name + '=');
  if (parts.length == 2) return parts.pop().split(';').shift();
}


// wait for the autoplay bar to appear and remove it
function removeAutonavElement() {
  var mutationObserver = new MutationObserver(function (mutations, mutationObserverInstance) {
    var element = document.getElementById('head');
   
    if (element) {
      element.remove();
      mutationObserverInstance.disconnect();
      return;
    }
  });
  
  mutationObserver.observe(document, {
    childList: true,
    subtree: true
  });
}


// set the autonav_disabled cookie (which appears sometimes but does not seem to have any effect)
function setAutonavDisabledCookie() {
 
  document.cookie = 'autonav_disabled=true; path=/; domain=' + cookieDomainValue;
}


// get the PREF cookie, search for the f5 key and set the required value to disable Youtube autoplay
function setAutonavDisabledPrefCookie() {
 
  var input = getCookie(prefCookieKey);
  var output = '';
  
  if (input && input.indexOf('=') !== -1) {
    var inputArray = input.split('&');
    var outputArray = {};

    var found = false;
    
    for (var i = 0; i < inputArray.length; i++) {
      
      var temp = inputArray[i].split('=');
      
      if(!temp[1]){
        
        temp[1] = '';
      }
      
      outputArray[temp[0]] = temp[1];
    }
    
    for (var key in outputArray) {
      
      if (key == prefCookieAutoplayToggleKey) {
        
        found = true;
        outputArray[key] = prefCookieAutoplayToggleValueAutonavDisabled;
      }
      
      if (output == '') {
        
        output = key + '=' + outputArray[key];
      } else {
        
        output = output + '&' + key + '=' + outputArray[key];
      }
    }
  }
  
  if (!found) {
    
    if(output == ''){
      
      output = 'f5=30000';
    }else{
      
      output = output + '&f5=30000';
    }
  }
  
  document.cookie = prefCookieKey + '=' + output + ';  path=/; domain=' + cookieDomainValue;
}


// bonus: set the "remind me later" cookie for the cookie consent bar
function setCookieConsentHideCookie(){
  
  document.cookie = 'HideTicker=true; path=/; domain=' + cookieDomainValue;
}

Bonus: To hide Youtube’s cookie consent bar, uncomment the first occurrence of setCookieConsentHideCookie(); in the script.