Fixing WhatsApp image dates after Android Migration

Recently I've had the issue to have a completely unsorted Photo Library in Android after migrating to a new phone. The reason is that WhatsApp images are copied into internal storage and end up with the last modification date when they were copied, thus conglomerating together when they should be spread out over time.

The problem is not that trivially to solve because you cannot mount internal storage into a computer and then modify the file dates. Thankfully, I was still able to create a viable solution using a bash script.

It all revolves around the Android Terminal Emulator Termux which allows you to execute scripts on your phone.

  1. Install Termux .
  2. Grant Termux access to your storage directories.
  3. Install core tools apt install coreutils
  4. Copy this script into your file tree (for example via Android File Transfer):
for f in IMG-20* VID-20* AUD-20*; do
    [ -e "$f" ] || continue
    NEWDATE=`echo $f | cut -c5-8`-`echo $f | cut -c9-10`-`echo $f | cut -c10-11`
    echo touch -d $NEWDATE "$f"
    touch -d $NEWDATE "$f"
  1. Run the script in the directories you need to fix file dates (for example in /storage/emulated/0/WhatsApp/Media/WhatsApp Images)
  2. Delete the data of MediaStorage (and maybe reboot) to make Android re-index the files with the new file dates.
Posted in web

Stack Overflow: Ways out of the negativity

This is in response to the Stack Overflow Meta question: Why is Stack Overflow so negative of late?

In my opinion the problem that Stack Overflow is currently facing is caused by a lot of new users that are characterized by user Mysticial as "help vampires". They care nothing for the site and just want their code fixed. They don't research (or very little) and provide less than the minimum information needed. Most of the times the questions are very basic and can be answered by an intermediate programmer in a few minutes.

In a normal forum, users would not yield any responses. Not so on Stack Overflow: you get reputation for answering questions and therefore even theses badly researched questions get answers within under a minute. Mystical calls these users "reputation whores".

The problem is that "help vampires" and "reputation whores" create a vicious circle: they both need each other and therefore the circle continues to spin.

The outcome of this situation: the site is flooded with a high number of low quality questions, experienced programmers who are interested in learning something don't see the forrest for the trees. Even though questions can be voted up, they don't stand out enough to gain momentum.

Proposed Solutions

a) Create a "beginners test"

This would create a higher burden for low reputation users before they can ask their question. They need to invest more time and rethink their action before they get to post something.

A few ideas what that could be:

  • The user needs to give 3 search queries that he used either on Google or on Stack Overflow that didn't yield results.
  • If they don't include any code, they must confirm that they are asking a non-code question. See this proposal on Stack Exchange Meta.
  • Specify the time that they took to research the problem (while this can be easily faked, it makes the user reconsider if they had taken enough time for the problem)

b) Have experienced users review a question, before it goes online

There would be a process where a new user asks his or her question, but it doesn't go online. Higher reputation users read the question but are unable to answer it, and give feedback if the question has enough information or has been researched enough. Finally, the question get's thrown into the shark tank.

It would be fine to give these reviewing higher reputation users even more reputation for reviewing this: they are helping to improve the site, this is actually what the reputation system has been designed for: to make the site interesting, not for feeding the "help vampires".

All in all it is remarkable that despite the current situation, Stack Overflow has reached the quality it has. The reputation and badge system has for sure been a very big factor in this but it is very appalling that in order to reach a certain reputation level, you really have to feed the "help vampires".

You can find me on Stack Overflow as akirk.

Posted in web

Fix qTranslate with WordPress 3.9

When updating a blog of mine to WordPress 3.9 the page wouldn't load anymore because of qTranslate not able to cope with the update. In the error log it says:

PHP Catchable fatal error: Object of class WP_Post could not be converted to string in ../wp-content/plugins/qtranslate/qtranslate_core.php on line 455

The error is caused by this change: get_the_date() to accept optional $post argument

There is a proposed quick fix by Saverio Proto, but it doesn't take the problem at its root:

qTranslate registers the function qtrans_dateFromPostForCurrentLanguage($old_date, $format ='', $before = '', $after = '') for the hook get_the_date but it actually only accepts one parameter. With the new update it accepts a second parameter $post, which now wrongly fills the variable $before that is in the process being converted to a string.

So the solution simply is to delete the two parameters that were assigned the wrong meaning and have defaults anyway.

Posted in web

Thinkery API launched

Just a quick note, we made the Thinkery API public.

If you don't know, it is a simple yet powerful tool for storing both notes and bookmarks. The contents of the saved page is stored in your Thinkery which you can keep even if the webpage goes down. With #hashtags you can easily categorize everything.

Check it out!

Posted in web

Genial Daneben Analyse

Zur Abwechslung mal ein Post auf deutsch. Ich bin Fan der (inzwischen abgesetzten) Fernsehsendung Genial daneben. Es gibt da eine Genial Daneben Datenbank mit (nahezu) allen Fragen, die in den Sendungen vorkamen. Ohne konkreten Nutzen habe ich diese Daten aus der Text-Form in eine echte Datenbank konviertiert (Script hier) und bin zu folgender Tabelle gekommen. Für alle die es interessiert:

Fragen: 2732 (1087 beantwortet, das sind fast 40%)

Teilnehmer Teilnahmen gelöst gelöst pro Teilnahme
Bernhard Hoecker 399 223 0.56
Hella von Sinnen 390 202 0.52
Wigald Boning 120 56 0.47
Guido Cantz 96 51 0.53
Barbara Schöneberger 62 14 0.23
Dieter Nuhr 62 18 0.29
Bastian Pastewka 62 6 0.10
Ralf Schmitz 60 6 0.10
Oliver Kalkofe 55 6 0.11
Herbert Feuerstein 47 25 0.53
Georg Uecker 39 13 0.33
Olli Dittrich 38 11 0.29
Oliver Welke 37 11 0.30
Ingo Appelt 32 8 0.25
Martin Schneider 31 0 0.00
Michael Kessler 29 6 0.21
Thomas Hermanns 27 7 0.26
Anke Engelke 26 8 0.31
Matze Knop 23 2 0.09
Christoph Maria Herbst 20 3 0.15
Mario Barth 20 8 0.40
Jürgen von der Lippe 19 3 0.16
Lou Richter 19 7 0.37
Ingo Oschmann 13 2 0.15
Guildo Horn 13 1 0.08
Dirk Bach 12 3 0.25
Kim Fisher 12 1 0.08
Urban Priol 10 2 0.20
Cordula Stratmann 9 0 0.00
Eckart von Hirschhausen 9 0 0.00
Tetje Mierendorf 8 0 0.00
Oliver Pocher 8 0 0.00
Bodo Bach 8 0 0.00
Hennes Bender 7 1 0.14
Rüdiger Hoffmann 7 0 0.00
Elton 7 1 0.14
Johann Köhnich 7 0 0.00
Bürger Lars Dietrich 7 2 0.29
Helge Schneider 7 7 1.00
Anka Zink 6 0 0.00
Hans Werner Olm 6 0 0.00
Cindy aus Marzahn 6 0 0.00
Kaya Yanar 5 2 0.40
Mike Krüger 5 2 0.40
Horst Lichter 5 2 0.40
Susanne Pätzold 5 1 0.20
Jochen Busse 5 1 0.20
Karl Dall 5 0 0.00
Mirja Regensburg 4 1 0.25
Oli Petszokat 4 2 0.50
Janine Kunze 4 0 0.00
Michael Mittermeier 4 0 0.00
Paul Panzer 3 0 0.00
Florian Schroeder 3 0 0.00
Konrad Stöckel 3 2 0.67
Axel Stein 3 0 0.00
Gayle Tufts 3 1 0.33
Verona Pooth 3 1 0.33
Zack Michalowski 2 0 0.00
Atze Schröder 2 1 0.50
Emily Wood 2 1 0.50
Susanne Fröhlich 2 0 0.00
Gabi Decker 2 0 0.00
Helfried 2 1 0.50
Mirja Boes 2 1 0.50
April Hailer 2 0 0.00
Michael "Bully" Herbig 2 1 0.50
Roberto Cappelluti 2 0 0.00
Olaf Schubert 2 0 0.00
Sissi Perlinger 2 0 0.00
Ottfried Fischer 2 0 0.00
Klaus Eberhartinger 2 0 0.00
Rick Kavanian 2 0 0.00
Lisa Feller 1 0 0.00
Sascha Korf 1 0 0.00
Marc Metzger 1 0 0.00
Joachim Fuchsberger 1 1 1.00
Martin Klempnow 1 0 0.00
Tom Gerhard 1 0 0.00
Ralph Morgenstern 1 1 1.00
Valerie Bolzano 1 0 0.00
Kurt Krömer 1 0 0.00
Hubertus Meyer-Burkhardt 1 0 0.00
Smudo 1 1 1.00
Badesalz (Gerd Knebel und Hendrik Nachtsheim) 1 0 0.00
Markus Maria Profitlich 1 1 1.00
Sven Nagel 1 0 0.00
Bernd Stelter 1 0 0.00
Matthias Matschke 1 0 0.00
Otto Waalkes 1 0 0.00
Till Hoheneder 1 0 0.00
Waldemar Hartmann 1 0 0.00
Lisa Fitz 1 0 0.00
Fatih Cevikkollu 1 0 0.00
Matze Knop (als Franz Beckenbauer) 1 0 0.00
Ralf Morgenstern 1 0 0.00
Ulrike von der Gröben 1 0 0.00

Ich habe den Großteil der Daten nicht überprüft, aber im Groben dürfte es stimmen.

Posted in web

Android WebView: Web page not available

Just a quick note in order to save someone else searching for a solution to this problem.

When you want to display HTML content in an Android WebView do it like this:

String html = "my >b<HTML content>/b<. 100% cool.";
WebView webView = (WebView) findViewById(;
webView.loadData(">?xml version=\"1.0\" encoding=\"UTF-8\" ?<" + html.replace("%","%25"), "text/html", "UTF-8");

If you don't replace the % to its url encoded equivalent you will get a "Web page not available". Simple, arguable but not at all apparent.

Posted in web

Git tip: Changing your mind: Push pending changes to a (not-yet existing) new branch

It happens quite often to me that I start committing things and only afterwards decide I should have created a new branch.

So git status says something like:

Your branch is ahead of 'origin/master' by 4 commits.

but I don't want to push to origin/master but rather create a new branch. (Of course this works for any other branch, not named master)

So you can use this sequence of commands:

git checkout -b newbranch
git push origin newbranch
git checkout master
git reset --hard origin/master

Explanation: This…

1. creates a new branch pointing to the current changes (and switches to it)

2. pushes this new branch including the changes to the server

3. switches back to the branch master
4. and undoes the changes that were made locally

The important thing to know is that the changes remain in the repository because a branch is merely a pointer to a commit.

Afterwards you can continue to commit to master, for example:

(screenshots done with a fork of gitx)

Posted in web

Use an authenticated feed in Google Reader

You currently can't subscribe to an authenticated feed (for example in Basecamp) in Google Reader.

If you want to do it nonetheless you can use this script of mine which will talk to the server that needs authentication, passing through all the headers (so that also cookies and "not modified" requests will come through): download authenticated-feed-passthru.php

// change this url
$url = "";

$ch = curl_init($url);

if (isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true);

$headers = array();
foreach ($_SERVER as $name => $value) {
    if (substr($name, 0, 5) != 'HTTP_') continue;
    if ($name == "HTTP_HOST") continue;
    $headers[] = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))) . ": " . $value;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

list($header, $contents) = preg_split('/([\r\n][\r\n])\\1/', curl_exec($ch), 2);

foreach (preg_split('/[\r\n]+/', $header) as $header) {

echo $contents;

If you don't mind giving away your credentials you can also use Free My Feed.

Posted in web