Using Newsblur's API

Everybody should have a feedreader for RSS feeds. Lately I decided to subscribe to some feeds of local organisations (like the zoo, some local fablabs or the nearest police station). Things that take place nearby are more interesting after all.

So yesterday I found that our city administration provides some RSS-feeds - many actually. They are all listed on this website. So I want to subscribe to all of them. I didn't find an easy way to subscribe to many feeds at once through the Newsblur web interface, so I decided it was a good day to test out the Newsblur api. (While the API is well documented, I found that I missed having some examples to play around with. So here is my example.)

For authentication I got my session coockie like this:

curl -X POST \
    --cookie-jar session.newsblur \
    --data "username=$MY_USERNAME" \
    --data "password=$MY_PASSWORD" \

After that, the file session.newsblur contains something that looks like a sessionid: TRUE / FALSE 1601234874 newsblur_sessionid xa3w22sometokenspecifictome6duds

As a test I tried reading a list of all my feeds (the json_pp is just for formating):

curl -X GET \
    --cookie session.newsblur \
    "" \
    | json_pp

This works just fine and contains information about my personal feeds, so we know I did the authentication right.

Next I want to subscribe to a single the feed (, taken from the site mentioned above) and add it in the folder regional. The documentation for this command tells us we will need to add the two arguments as url parameters. Since the url contains suspicious caracters like :, ., / and \ (that are likely to break things) I will use the curl flag --data-urlencode:

curl -X POST \
    --cookie session.newsblur \
    --data-urlencode "url=" \
    --data-urlencode "folder=regional" \

The output again is some json, telling my information about the newly subscribed feed:

      "subs" : 1,
      "feed_link" : " - Ausstellungen",
      "id" : 7686975,
      "min_to_decay" : 240,
      "updated_seconds_ago" : 15878,
      "stories_last_month" : 6,
      "favicon_text_color" : "white",
      "fetched_once" : true,
      "search_indexed" : true,
      "last_story_seconds_ago" : 541185,

A look at the Newsblur's website tells us that we really did subscribe to the feed and it was placed in the correct folder. So we are nearly there! Let's get a list of all the feeds that are linked in the site of the city administration:

lynx -dump -listonly "" \
    | grep xml | awk '{print $2}' > feeds_to_subscribe_to.txt

We get a file with one feed address per line (36 in sum). Now all that is left is to loop over them and subscribe to them one by one.

cat feeds_to_subscribe_to.txt | while read feed
        curl -X POST \
            --cookie session.newsblur \
            --data-urlencode "url=$feed" \
            --data-urlencode "folder=regional" \
        sleep 1 # don't spam the api

And there we go: We subscribed to each of the feeds listed on the website.

I didn't have much opportunity to work with APIs, yet. But it was fun to play around with this one, there is nothing to be afraid of.

My wifes macbook didn't start anymore, it tried but went into the same error again and again. This is how I got the data from the old hard drive.

  1. Get yourself a drive to rescue the files to (we will call it LIFEBOAT). Connect it to the mac.

  2. Enter Recovery mode by pressing CMD and R at startup.

  3. Get yourself a terminal (in the upper menu under "Utilities").

  4. Make sure LIFEBOAT can be found under /Volumes/LIFEBOAT.

  5. Make sure your userdata is in /Volumes/Macintosh HD/Users/YOURUSERNAME.

  6. Copy the files you need to the LIFEBOAT with a simple cp -r command.

  7. Close the Terminal (CMD-Q) and shut down the Mac.

The critical step is clearly step 5. If the data is not there, I have no idea what to do.

The mac I used was running an old version of OSX (Mavericks) and I think in the newer ones the files might be encrypted.

I did have two backup plans:

  • Try to find whatever is left from the files with TestDisk, perhaps after copying the drive to make sure I don't destroy anything by excident. This was a recommendation of Pascal and David.

  • Pay someone to rescue as much data as possible. There are companies for this.

In the end I was very glad to get everything back.

Most of us know awk as the program that you use when you want only that one column of your output. Just pipe it through awk '{print $3}' and the third column you get.

Fewer people know that awk is a programming language. It is specialized for processing structured input like tables.

As an example we will analyze this table of events at of the first Quidditch match of the first Harry Potter book, Griffindor vs Slytherin.

player team points
Johnson Griffindor 10
Spinnet Griffindor 10
Flint Slytherin 10
Flint Slytherin 10
Flint Slytherin 10
Flint Slytherin 10
Flint Slytherin 10
Flint Slytherin 10
Potter Griffindor 150

You can run all the awk programs in this blogpost with awk -F, 'PROGRAMM' quidditch.csv or by saving the awk-program into a file and running awk -F, -f 'PROGRAMMFILE' quidditch.csv. The file can be found here, it is the table from above with columns separated by ,.`

Get values from column 3

In awk we think of the input as a sequence of records (lines normally) that consists of sequence of fields (words). These fields can be adressed by $1, $2 etc (and $0 is the whole record).

Lets extract the column "points": The third field of each record.

{print $3}

Of course the header is not interesting here and we should remove it.

Remove the header

The syntax of awk is a bit different from the programming languages you might know. In man awk we read:

An awk program is a sequence of patterns and corresponding actions. When input is read that matches a pattern, the action associated with that pattern is carried out.

So a program is a series of statements like this:

<script type="text/javascript" src=""> </script>

$$\stackrel{\text{If the input matches this pattern ....}}{\overbrace{\text{pattern}}}\underset{\text{... then run this action on it}}{\underbrace{\left\{ \text{action}\right\} }}$$

In the case of our program above a special case zoccurs: If there is no pattern given every record matches.

To remove the header of the results we can simply add a condition to the program: Don't act on the first line (the record where the record number NR is 1).

NR!=1 {print $3}

Sum of a column …

Now lets get the sum of all the points scored by the players. Our first thought here is to pipe the result into the program sum. But interestingly enough there is no such program in the world of commandlines as far as I know. It seems like our ancestors with their great beards were fine with writing their own version when they saw need to. And when they did they probably used awk.

NR!=1 {points+=$3}
END{print points}

Two things should be noted here:

  • the line marked with END is only triggered after all the input has been processed. There is a similar keyword (BEGIN) which allows code to be executed before the rest of the code. (Dough!~)

  • the variable points did not have to be initialized. awk is full of sensible defaults and one of them is that a numerical variable with no value is assumed to have the value 0 if not stated otherwise.

… grouped by another column

To get the result of the Quidditch match we need to sum the points for every team separately. We can use arrays (which would be called dict in other languages) for that.

NR!=1 {points[$2]+=$3}
END {for (key in points) { print key " " points[key]}}
Griffindor 170
Slytherin 60

And here we have our final score of the game.

I really know only one other language which can do this sort of processing with so little code: SQL. But SQL only works for databases so it needs a big setup to be useful. So when I find myself with a bunch of text files in a unixoid environment, then awk is the way to go.

Oh, and if you think Griffindor totally dominated this match, here is how the score would have looked like if Harry hadn't caught the snitch (which happened more or less by luck).

NR!=1 && $1 !~ "Potter" {points[$2]+=$3}
END {for (key in points) { print key " " points[key]}}
Griffindor 20
Slytherin 60

Die letzten Tage habe ich auf der PyconGermany in Karlsruhe verbracht. Die dominanten Themen waren Machine learning, Docker und vielleicht noch ein bisschen BigData. Über Python2 redet eigentlich keiner mehr, das ist schön.

Ich habe viel gelernt und einige spannende Leute getroffen (schöne Grüße an Corrie). Irgendwie schafft es die Pythoncommunity, ein breiteres Feld als die üblichen Nerds anzusprechen (zu denen ich mich selbst dazu zählen würde). Insbesondere das Verhaeltnis Maenner:Frauen war erfreulich ausgeglichen, wenn auch noch nicht 1:1.

Dort habe ich meinen ersten Lightningtalk gehalten. Ich war sehr aufgeregt, zumal der Vortrag auf Englisch sein sollte. Aber es lief sehr gut, ich habe das Zeitlimit eingehalten und die Aha-Momente sind übergesprungen. Ich bin sehr zufrieden.

Für die Slides habe ich Remark.js verwendet: Man hat eine html-Datei, den eigentlichen Inhalt schreibt man im Markdownformat. Das wird dann vom Javascript in Folien umgewandelt, wenn man die Datei im Browser öffnet. Das ist ein cleveres Format, weil es mehrere Vorteile vereint:

  • Schreiben in Markdown
  • Styling mit der Macht von HTML und CSS
  • Code Highlighting mit highlight.js
  • Nur ein einzelnes, schlankes Dokument (zumindest solange man keine Bilder einbettet)
  • Läuft auf jedem OS, das einen Browser hat.
  • Es gibt ein minimales Interface für den Praesentierenden, in dem Notitzen, ein Timer und die nächste Folie angezeigt wird. Hilfe gibt es mit h oder ?.

Interface fuer den Praesentierenden.

Ein paar Schwierigkeiten habe ich aber noch:

Es ist knifflig, offline zu präsentieren, weil Remark.js aus dem Netz nachgeladen wird. Gerade auf Konferenzen ist stabiles Netz ja keine Selbstverständlichkeit. Man kann das natürlich lösen, indem man das Repo klont und die lokale Version lädt, aber dann ist es halt nicht mehr so portabel.

Außerdem habe ich ein bisschen die Allmacht von Orgmode vermisst, Code einzubinden und den Output direkt generieren zu lassen. Aber das ist ein Luxusproblem, wer Orgmode will muss eben Orgmode benutzen.

Insgesamt war ich mit Remark.js sehr zufrieden und würde es für Praesentationen wieder verwenden. Andererseits kenne ich mich gut genug um zu wissen, dass ich selten zweimal das gleiche Setup für meine Grafiken und Folien verwende. Es gibt einfach zu viele spannende Tools.

Start videos from the commandline

tldr: Just use mpv VIDEOURL to start watching.

Lets say you want to watch a video, how would you do it from the commandline?

local video file

If the file you want to see is already on your computer, then this can't be too hard. Just go with your favorite video player (vlc in this example):

vlc ~/Videos/Nyan_Cat.mkv

videos from the internet

So what if the video isn't already downloaded? Lets say we want to look at this YouTube Video: Nyan Cat.

No problem, we can download it right away with youtube-dl.

youtube-dl -o "~/Videos/Nyan_Cat.mkv" "" && vlc ~/Videos/Nyan_Cat.mkv

The reason why we don't use curl/wget here is that we don't have the url of the video file itself (and if we did, we could just continue to feed it into vlc directly). The video is embedded into a website and there is no trivial way to get its url. If we ask youtube-dl nicely (with --get-url) he will tell us, but at this point we have used youtube-dl anyway, so what's the point?

The video that google uses has a really long url. Something tells me that is isn't meant for direct use.

Youtube-dl is quite amazing. It supports a great number of video sites and file formats. It also supports playlists, logins for private videos and downloading the audio only. Being controlled from the commandline makes it scriptable, but the best thing about it is that it has been under continuous development for many years now, catching up with all the api-changes from all the supported websites.

streaming, not downloading

Downloading works, but what if we want to start to watch straight away, waiting for the download to finish is unnecessary (especially if the video is a big one, like the 10 hour version of the video above).

Youtube-dl can write the file to stdout (--output -) and tell the video-player to play from stdin (vlc - in this case).

youtube-dl --output - '' | vlc -

Unfortunatelly there is no easy way to jump positions in the videos itself.

mpv to the rescue

vlc has a big fanbase, but for quite some time I preferred to use mplayer, because it has the most minimal gui imaginable (a window whith the video in it, nothing more) and is easier to use from the keyboard. Then I found mpv, a pimped version of mplayer - and everything is perfect. Much like feh for images, it does all I want and goes out of the way otherwise. I just love it.

Mpv makes all the problems from above trivial.

mpv ''

It uses youtube-dl, can show subtitles in different languages, jumps between positions and has an easy syntax. It is free software (like all the other programs I talked about in this post) and its development continues steadily.

Why not use a browser, like a normal person?

Using a native video-player comes with some cool bonuses. You can configure and finetune it, use media-keys on your keyboard, it plays nicely with the rest of your setup and your window-manager etc.

The only downside I see is that the resolution is not adjusted on the fly if the connection is not good enough to stream in full resolution. That's why I still use a browser for twitch-streams.

Wieder da

Ich bin wieder da. Der Blog hat lange geruht und jetzt habe ich Lust, wieder zu schreiben.

Der Blog war auch und vor allem deshalb fort, weil wir unseren geliebten Server Gipfelsturm verloren haben. Da sind auch Sandras und mein Ghostblog drauf gewesen und ich wollte erst wieder schreiben, wenn ich beide Blogs wieder so weit habe, dass sie benutzt werden können (Es wäre unfair gewesen, selbst weiter zu bloggen bevor ihr Blog wieder läuft).

Dazu musste ich aber aus schlechten Backups die meisten Artikel wieder herzaubern (viel habe ich von und dem google-cache gezogen, Viele Bilder hatten wir noch undeinige konnten wir wieder zuordnen) und eine ganz neue Bloginfrastrucktur aufbauen. Das war eine lange Reise, aber jetzt bin ich ganz zufrieden. Vielleicht schreibe ich später mehr zu den Details. Die Hauptsache ist, dass ich jetzt große Kontrolle über den Blog habe (wenn was nicht geht kann ichs wahrscheinlich reparieren) und es trotzdem einfach ist, zu bloggen.

Es läuft wieder was in der Schauderbasis.

PS: Der RSS-Feed funktioniert auch:

Bilder aussortieren

Es gab eine Feier, jemand hat Fotos gemacht und rumgeschickt. Oder vielleicht habe ich selbst hundert mal den selbe Essen fotografiert. Jedenfalls sind da ein Haufen Bilder und ich will nur die guten behalten.

Dieses Aussortieren macht wenig Spaß und soll deshalb schnell gehen. Wenn man es gut macht hat man danach nur noch 5-10% der Bilder. Der Lohn: Man kann den wenigen guten Bildern viel mehr Beachtung schenken.

Erstaunlicherweise bietet der einfachste (und schnellste) mir bekannte Imageviewer dafür das beste Interface bereit: feh


Wir bilden den Sortierprozess auf das Filesystem ab. Wärend dem sortieren haben wir 3 Haufen von Fotos:

  • die noch unsortierten Fotos (~/Pictures/feier)
  • die guten Fotos (~/Pictures/feier/good)
  • die schlechten Fotos (~/Pictures/feier/bad)
mkdir ~/Pictures/feier
cd ~/Pictures/feier
mv ~/Downloads/ .
mkdir good bad

Wir werden die schlechten Bilder erst wegwerfen wenn wir mit dem sortieren ganz fertig sind (so vermeiden wir unglückliche Versehen).


Hier steckt die ganze Magie drin:

feh --auto-zoom --scale-down --action1 "mv %f good/" --action2 "mv %f bad/" .

Übersetzt bedeutet das: “Zeige alle Bilder im aktuellen Verzeichnis (.) nacheinander (als Slideshow) an, so gezoomt das man immer das ganze Foto sehen kann. Wenn ich die Taste 1 drücke, verschiebe das aktuelle Bild ins Verzeichnis good, wenn ich 2 rücke verschiebe es nach bad.”

Nette Annehmlichkeiten sind dabei:

  • Wenn man gerade nicht sicher ist, kann man mit den Pfeiltasten einfach zum nächsten Bild springen und die Entscheidung verschieben.
  • Ein Bild, bei dem man eine Wahl getroffen hat wird nicht mehr angezeigt. Sind keine Bilder mehr übrig, wird das Programm beendet
  • Will man unterbrechen, hilft die Taste q, was man bisher sortiert hat bleibt auch sortiert.
  • feh ist zwar schlank und klein, aber zum zoomen und Bilder richtig herum drehen reicht es noch.
  • Wie die meisten Unix-workflows ist auch dieser sehr flexibel. Ideen, die man damit schnell verwirklichen könnte:
    • einen dritten Ordner (bin_nicht_sicher)
    • mehrere Sortierdurchläufe.
    • Photos taggen
  • Das Interface ist so einfach wie nur irgend möglich: Man sieht nur das Bild und hat genau 2 Tasten für 2 Möglichkeiten.
  • Es geht schnell. Wenn man mal ein bisschen drin ist hat man schnell einige Hundert Bilder sortiert.


Zum Schluss (und wenn man sich sicher ist) wirft man die schlechten Fotos weg und behält die guten:

rm bad/* -f
mv good/* .
rmdir good bad

Bilder von hier und hier.

Hörbücher auf SailfishOS

Unterwegs höre ich sehr gerne Hörbücher - besonders in vollen öffentlichen Verkehrsmitteln, wo man ohnehin nicht viel anderes machen kann als Musik/Podcasts/Hörbüchern zu lauschen oder seinen Feedreeder durchzuarbeiten. Auf SailfishOS gibt es keinen nativen Client, aber die Standardapp “Medien” funktioniert wunderbar. Wie ist also der Workflow?

Umweg über den Rechner

Bestimmt geht das auch direkt auf dem Telefon, aber ehrlich gesagt habe ichs noch nicht ausprobiert. Außerdem geht es dank ssh/scp sehr flott auch von der Kommandozeile.

Hörbuch finden

Ich könnte es gar nicht besser zusammenschreiben als es im Wiki Audiobooks Subreddit steht.

Für diesen Blogpost wählen wir The Wrong Box auf Librivox.

Hörbuch herunterladen

Hörbücher sind meistens mehrere Audiodateien, zum Beispiel eine für jedes Kapitel. Meistens bekommt man diese schön kompakt in einer zip-Datei, die lädt man herunter und entpackt sie. Manchmal sieht man aber auch nur eine Website voll mit Links zu dein einzelenen Dateien (wsl für Leute, die alles direkt im Browser konsumieren wollen). In diesem Fall hilft dieser Befehl.

lynx -dump | grep 64kb.mp3$ | awk '{print $2}' | xargs -n1 wget

In Worten: Schau dir alle Links der genannten Webseite an, nimm die die auf “64kb.mp3” enden und lade sie einzeln herunter. (Es könnte also schlau sein, das in einem leeren Ordner auszuführen.)

Bei librivox ist das aber eigentlich nicht nötig, man kann alles direkt herunterladen (sogar per Torrent, wohooo!).

Es macht übrigends alles (erheblich) einfacher, wenn die Dateien so benannt sind, dass die alphabetische und die logische Ordnung übereinstimmen.

ssh aufs Telefon

Testweise kann man sich schonmal aufs Telefon verbinden und den Ordner anlegen, wo die Dateien später liegen sollen. Ssh muss in den Einstellungen des Telefons unter “Entwicklermodus” aktiviert werden, dort findet man auch Passwort und IP-Adresse.

ssh nemo@
mkdir Music/wrong_box

Hörbuch aufs Telefon

Da wir ja jetzt schon alles vorbereitet haben, reicht ein kurzes Befehl:

scp *.mp3 nemo@

Das wars schon.


Wir können alles in der Medien-App anhören. Nach dem aktuellen Kapitel wird automatisch zum nächsten gesprungen.

Firefox History in der Kommandozeile

Firefox ist so bekannt geworden, weil man alles mögliche an ihm einstellen kann. Warum ist es dann so schwer, ihn von der Kommandozeile zu steuern?

Ich würde wirklich gerne ein paar Skripte schreiben, welche die aktuell geöffneten Seiten von Firefox auswerten (zum Beispiel um die aktuelle Seite in eine Liste einzutragen, einen Eintrag in meinen Passwortmanager zu machen oder ähnliches).

Leider ist das scheinbar sehr schwierig, denn dieser riesige Kloß von einem Browser kann scheinbar nicht nach außen kommunizieren (Ich arbeite gerade mit Mozilla Firefox 46). Folgenden Notbehelf habe ich gefunden:

Die neuste Seite ist aktuell

Ich nehme vereinfachend an, dass ich mich nur für die Seite interessiere, die als letztes aufgerufen wurde. Dann muss man nur in der Firefox History nachschauen, welche Seite die letzte war und sie ausgeben.

Warum ist das leichter? Firefox speichert seine History, Bookmarks und noch ein paar andere Dinge in einer sqlite Datenbank: $HOME/.mozilla/iwfal82r.default/places.sqlite. (Der Teil vor “default” sieht jedes mal ein bisschen anders aus, aber das findet man schon. Im Folgenden benutze ich ein Regexsternchen, so dass die Befehle bei jedem funktionieren sollten.) Da ich ja neulich schon etwas Erfahrung mit Datenbanken gesammelt habe, wage ich mich da mal rein.

So sieht eine Datenbank von innen aus

In der Datenbank

sqlite3 $HOME/.mozilla/firefox/*.default/places.sqlite

SQLite version 3.13.0 2016-05-18 10:57:30
Enter ".help" for usage hints.

Wir sind jetzt in der Datenbank (raus kommen wir mit Ctrl-D). Erstmal schauen wir was es hier für tables gibt:

sqlite> .tables
moz_anno_attributes  moz_favicons         moz_items_annos    
moz_annos            moz_historyvisits    moz_keywords       
moz_bookmarks        moz_hosts            moz_places         
moz_bookmarks_roots  moz_inputhistory  

Die Tabelle die wir brauchen ist die moz_places. Hier ist unsere gesamte Browserhistory drin (habe ich hier rausgefunden). Wir schauen uns die Spalten der Tabelle an:

sqlite> pragma table_info(moz_places);

Für uns sind url und last_visit_date wichtig (denn wir wollen ja die URL, die zuletzt aufgerufen wurde). Wir tasten uns mal langsam ran:

Alle URLS, die ich je aufgerufen habe

Alphabetisch sortiert.

sqlite> select url from moz_places;
Alle URLS, die ich je aufgerufen habe

Nach Datum sortiert.

sqlite> select url from moz_places order by last_visit_date;
Wann die letzte URL aufgerufen wurde
sqlite> select max(last_visit_date) from moz_places;

Hmm, eigentlich sollte hier ein Datum stehen. Laut table_info ist dieses als Integer kodiert. Das Internet hilft weiter.

sqlite> select max(last_visit_date) as raw_visit_date,datetime(last_visit_date/1000000,'unixepoch') from moz_places;
1464029535578940|2016-05-23 18:52:15

Sieht doch gleich viel besser aus, die ISO 8601 lebe hoch. Aber irgendwie ist das um zwei Stunden falsch? Ach ja, Zeitzonen.

sqlite> select max(last_visit_date) as raw_visit_date,datetime(last_visit_date/1000000,'unixepoch','localtime') from moz_places;
1464029535578940|2016-05-23 20:52:15

Geht doch.

Eigentlich brauchen wir diese schick formatierten Strings aber gar nicht, wir wollen ja nur nach Zeit sortieren. Deswegen orientieren wir uns am ersten Versuch.

Die URL, die ich als letztes besucht habe

Genau genommen fragen wir eher nach allen urls, die zu dem Zeitpunkt aufgerufen wurden, an dem wir zuletzt eine url aufgerufen haben.

sqlite> select url from moz_places where last_visit_date=(select max(last_visit_date) from moz_places);

Hurra, es funktioniert!

Für Skripte

Damit wir uns nicht ständig in sqlite einloggen müssen, kann man das auch von außen tun.

$ sqlite3 $HOME/.mozilla/firefox/*.default/places.sqlite "select url from moz_places where last_visit_date=(select max(last_visit_date) from moz_places)"

So, da ist sie. Die letzte besuchte Url. Das funktioniert, auch sofort nach dem Aufrufen der Url oder wenn der Firefox aus ist.

Bilder von hier und hier