RSS2Queet

Das letzte, was mir für den Abschluss meines Umzugs¹ vom Zwitscherchen zu Quitter (eine GNUsocial-Instanz) noch fehlte, war ein Ersatz für das bequeme automatische Wegzwitschern aktualisierter Blogbeiträge.

Zum Glück ist die API relativ einfach nutzbar, solange man kein OAuth benötigt. Es ist zum Beispiel möglich, mit einem Shellskript einen Queet abzusetzen – wobei ich hier natürlich die Zugangsdaten unkenntlich gemacht habe:

#!/bin/sh
api='https://quitter.se/api/statuses/update.xml'
username='xxxxxxxx' # Quitter-Benutzername hierher
password='xxxxxxxx' # Quitter-Passwort hierher
curl -u "$username:$password" "$api" -d status="$*" >/dev/null

Für eine wirklich komfortable Lösung des Problems brauchte ich freilich etwas mehr Aufwand.

  1. Eine beliebige Menge RSS-Feeds soll überwacht werden
  2. Alle Artikel, die seit dem letzten Abholen des Feeds hinzugekommen sind, sollen in Queets verwandelt werden.
  3. Der Queet soll den Titel des Postings und einen möglichst kurzen Link enthalten. (Auf URL-Kürzer habe ich vorerst verzichtet.)
  4. Es soll mit Leichtigkeit möglich sein, den Aufruf in die crontab zu schreiben.

Das Ergebnis ist folgendes, verblüffend kompliziert aussehendes Python-Skript, das aber nur so kompliziert aussieht, weil ich es ganz schnell geschrieben habe. Passend zum Quick-and-Dirty-Stil habe ich auf jede halbwegs verantwortungsvolle Fehlerbehandlung verzichtet…

#!/usr/bin/env python
# -*- coding: utf-8 -*-
########################################################################
#
# rss2queet.py
# $Id: rss2queet.py,v 1.9 2014/09/16 22:32:54 elias Exp $
#
# Das muss ich leider in Python 2 coden, weil ich auf dem Serverchen
# kein anderes Python habe. (Ich halte die Installation dort so klein
# wie möglich).
#
# Eine Portierung nach Python 3 ist relativ aufwändig.
#
# Und ja, ich weiß, wie dieser Code saugt. Ich habe ihn sehr schnell
# geschrieben, weil ich ihn haben wollte, um schneller von Twitter
# wegzukommen. Er gewinnt keine Ästhetikpreise und hat mich trotz des
# allgegenwärtigen Quick-and-Dirty-Stils länger aufgehalten, als ich
# mir gewünscht habe. Fehlerbehandlung fehlt völlig.
#
# Dieses Skript ist unter den Bedingungen der Piratenlizenz lizenziert
# https://www.tamagothi.de/impressum/lizenz/
#
########################################################################

import ConfigParser
import os.path
import xml.dom.minidom
import re
import datetime
import time
import urllib
import httplib


########################################################################
#
# Konfiguration
# -------------
#
# Hier werden einfach alle URLs der RSS-Feeds in ein Array eingetragen.
# Der Rest verläuft "automagisch".
#
# Hier sind einfach die RSS-Feeds meiner Blögchen eingetragen.
#
feeds = [ 'http://schwerdtfegr.wordpress.com/feed/',
          'http://spam.tamagothi.de/feed/',
          'https://www.tamagothi.de/author/elias/feed/',
          'http://alarmknopf.wordpress.com/feed/',
          'http://gagada.wordpress.com/feed/',
          'http://fraktalwelten.wordpress.com/feed/',
          'http://tamagothi.wordpress.com/feed/',
          'http://proll.wordpress.com/feed/',
          'http://wwwut.wordpress.com/feed/',
        ]
#
# API-Entrypoint für den Statusupdate
# Hier kann natürlich auch ein anderer Einstiegspunkt stehen.
#
api_update = 'https://quitter.se/api/statuses/update.xml'
#
# Username
#
username = '----'
#
# Passwort
#
password = '----'
#
# Da diese Datei ein Passwort im Klartext enthält, sollte sie vielleicht
# nicht mit chmod 666 abgelegt werden. ;)
#
# In den meisten Fällen braucht ab hier nicht mehr angepasst zu werden.
#
########################################################################
#
config_path = os.path.expanduser('~/.rss2queet')
#
# Ab hier gibts nichts mehr, was angepasst werden muss.
# Vielleicht erschlägt mal jemand die Fehler, die ich gemacht habe... :D
#
########################################################################

# Globale Variablen
# -----------------

config = ConfigParser.ConfigParser()
time_now = int(datetime.datetime.utcnow().strftime('%s'))
timestamp_re = re.compile(r' *\+\d*$')


# Programm
# --------
#
# Sorry, auf hilfreiche Kommentare wurde weitgehend verzichtet.

class AuthURLOpener(urllib.FancyURLopener):
    version = 'RSS2Queet/0.2beta'
    
    def get_user_passwd(self, host, real, clear_cache=0):
        return (username, password)

urllib._urlopener = AuthURLOpener()


def init():
    config.read(config_path)


def cleanup():
    config.set('DEFAULT', 'lastrun', time_now)
    f = open(config_path, 'wt')
    config.write(f)
    f.close()
    

def make_unix_timestamp(time_string):
    # ARRGH!
    # No better way than strptime and ignoring timezone in Python 2.
    cleaned_up = timestamp_re.sub('', time_string)
    return datetime.datetime.strptime(cleaned_up, '%a, %d %b %Y %H:%M:%S')


def queet_item(text, link):
    message = u"%s %s" % (text, link)
    message = message.encode('ascii', 'xmlcharrefreplace')
    data = urllib.urlencode({u'status': message})
    r = urllib.urlopen(api_update, data)
    

def get_text_easy(nodelist):
    accu = []
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            accu.append(node.data)
    return u''.join(accu)


def get_node_text(node):
    return get_text_easy(node.childNodes)


def get_item_pubdate(item):
    pubdate_str = get_node_text(item.getElementsByTagName('pubDate')[0])
    return make_unix_timestamp(pubdate_str)


def handle_item(item, lastrun):
    item_timestamp = get_item_pubdate(item)
    last_timestamp = datetime.datetime.fromtimestamp(lastrun)
    if item_timestamp <= last_timestamp:
        return
    item_title = get_node_text(item.getElementsByTagName('title')[0])
    item_uri = get_node_text(item.getElementsByTagName('guid')[0])
    queet_item(item_title, item_uri)
    

def handle_item_list(item_list, lastrun):
    for item in item_list:
        handle_item(item, lastrun)


def handle_channel(channel_doc, lastrun):
    handle_item_list(channel_doc.getElementsByTagName('item'), lastrun)

    
def get_document_for_feed(feed_url):
    return xml.dom.minidom.parse(urllib.urlopen(feed_url))


def handle_feed(feed_url):
    if not config.has_section(feed_url):
        config.add_section(feed_url)
        config.set(feed_url, 'lastrun', time_now)
    else:
        lastrun = config.getfloat(feed_url, 'lastrun')
        config.set(feed_url, 'lastrun', time_now)
        handle_channel(get_document_for_feed(feed_url), lastrun)


def main():
    init()
    for feed_url in feeds:
        handle_feed(feed_url)
    cleanup()


if __name__ == '__main__':
    main()

In der Hoffnung, dass es anderen Menschen ein kleines bisschen Arbeit abnimmt, steht das Skriptchen hier zum freien Download zur Verfügung. Es kann unter den Bedingungen der Piratenlizenz benutzt, bearbeitet, verbreitet oder verschrottet werden. Viel Spaß damit!

Kleine Anmerkung: Wenn das Skript zum ersten Mal für einen neuen Feed gestartet wird, holt es diesen Feed noch nicht ab, sondern setzt nur die aktuelle Zeit als Zeitpunkt der letzten Abholung. Auf diese Weise wollte ich vermeiden, dass die Statusmeldungen bei Quitter mit großen Mengen alter Texte vollgespammt werden.

¹Warum? Weil das Zwitscherchen nun für mich entscheiden will, welche Beiträge wichtig sind und welche nicht und weil ich das scheiße finde. Von den jüngsten Geschäftsideen eines börsennotierten Unternehmens ohne seriöses Geschäftsmodell einmal ganz abgesehen.

Veröffentlicht unter Technisches | Verschlagwortet mit , , , , , | Kommentar hinterlassen

Was Twitter-Nutzer demnächst lesen dürfen…

Die folgende Mail ist bei einigen Twitter-Nutzern angekommen. Ich zitiere sie hier in anonymisierter Form ohne weiteren Kommentar. Die holprige Sprache, die sich teilweise wie eine schnell überarbeitete Google-Übersetzung eines englischen Textes liest, entspricht dem Original. Ich habe einige Stellen mit besonders fragwürdigen Ausdrucksweisen durch sic! gekennzeichnet.

Von: Twitter <info (at) twitter (punkt) com>
Gesendet: Freitag, 12. September 2014, 20:xx Uhr
Betreff: Die neuesten Produkt- und Richtlinien-Updates von Twitter

Hallo [Hier stand der Twitter-Name],

Wir haben unsere Datenschutzbestimmungen und Allgemeinen Geschäftsbedingungen aktualisiert

Wir haben unsere Allgemeinen Geschäftsbedingungen und Datenschutzbestimmungen aktualisiert, um neue Funktionen, die wir gerade testen (beginnend in den USA), widerzuspiegeln [sic!]. Dadurch möchten wir Dir ermöglichen, Fanartikel [sic!] von einigen der beliebtesten Vertreter auf Twitter zu erwerben, ohne dabei Twitter zu verlassen.

Die Aktualisierung der Allgemeinen Geschäftsbedingungen bringt Bedingungen ein [sic!], die die Nutzung unserer Handelsangebote [sic!] umfassen. Die neuen Bedingungen beschreiben außerdem Dein Verhältnis zu Verkäufern von Fanartikeln [sic!], einschließlich ihrer Verantwortung für die Auftragsabwicklung, Lieferung und Rückgabe.

Und da Du bestimmte Informationen angeben musst, um einen Kauf zu tätigen, z.B. eine Kreditkartennummer und Lieferadresse, beinhaltet die Aktualisierung der Datenschutzbestimmungen neue Abschnitte bezüglich dieser Informationen. Dir werden ebenfalls Bestimmungen bezüglich Handelsdienstleistungen angezeigt, die wir in Zukunft testen werden, wie z.B. spezielle Angebote, die Du in ausgewählten Geschäften mit Deiner Kreditkarte einlösen kannst.

Wir haben die Datenschutzbestimmungen auch aktualisiert, um zu verdeutlichen, wie andere Bereiche unseres Dienstes funktionieren [sic!]. Dazu gehört Folgendes:

  • Dass wir möglicherweise um zusätzliche Accountdaten bitten [sic!], um Spam, Betrug oder Missbrauch zu vermeiden.
  • Die breite Masse, die öffentliche Profilinformationen und Tweets erhält [sic!], einschließlich Suchmaschinen, Anbieter und Herausgeber [häh!].
  • Die Arten von nicht-privaten oder nicht-persönlichen Informationen, die mit anderen geteilt werden, einschließlich Erfahrungsberichten an Werbeträger [sic!] über die Darbietung ihrer Werbekampagnen.
  • Wie wir bestimmte Arten von Informationen sammeln, einschließlich Ortsangaben (wie z.B. durch die IP-Adresse oder Zugangspunkte in der Nähe) und Informationen darüber, wenn Du über Twitter eine andere Applikation installierst.
  • Dass wir möglicherweise übereinstimmend mit unseren jeweiligen Datenschutzbestimmungen Daten mit unseren Tochterfirmen teilen [sic!], z. B. wenn Du Deine Twitter Anmeldedaten nutzt, um Dich bei Vine, unserem Dienst für kurze Videos, anzumelden, oder um durch MoPub, unsere auf Mobiltelefone konzentrierte Werbebörse, bessere Werbung anzuzeigen [sic!].

Wir haben ständig weitere spannende Produktneuheiten [sic!], behalte also den offiziellen Twitter Blog im Auge oder folge @twitter , um auf dem Laufenden zu bleiben. Danke, dass Du Twitter nutzt!

– Das Twitter Team

Ich wünsche euch allen auch in Zukunft viel Spaß mit den Monetarisierungsversuchen eines börsennotierten Unternehmens ohne seriöses Geschäftsmodell.

Diese E-Mail von Twitter wurde mir von @balouqlc@quitter.se zugesteckt.

Veröffentlicht unter Allgemeines | Verschlagwortet mit , , , , , | 2 Kommentare

Was ich regelmäßig vermisse

Was ich unter den Hinweisen des Landeskriminalamtes Niedersachsen, wie man mit seiner Internetnutzung nicht zum Opfer krimineller Banden wird neben unsinnigen Aufforderungen wie »Kaufen sie ein kostenpflichtiges Antivirus-Schlangenöl, weil das besser wirkt als das kostenlose Schlangenöl« vermisse, ist der Hinweis, einfach auf das Lieblingsbetriebssystem der Kriminellen zu verzichten; zumindest fürs Internet nicht Microsoft Windows einzusetzen, diese Software für zukünftige Opfer, sondern ein Betriebssystem, das alles für diesen Zweck Benötigte kann. Kombiniert mit einer laientauglichen Anleitung, wie man ein anderes Betriebssystem als Microsoft Windows in einer virtuellen Maschine zum Laufen bringt (das ist sehr einfach), könnte dieser Tipp zusammen mit der dort gegebenen Aufklärung mehr gegen die widerwärtige Kriminalität bewirken als der ständig wiederholte Verweis auf den Antivirus-Bullshit. Einmal ganz davon abgesehen, dass es sehr einfach ist, dann zusätzlich eine zweite virtuelle Maschine nur für Geschäfte und Online-Banking aufzusetzen, die von der alltäglichen Internetnutzung mit allen damit verbundenen Risiken abgekoppelt ist.

Aber ich bin ja auch kein Polizist… 😉

Veröffentlicht unter Allgemeines | Verschlagwortet mit , , , , , , | Kommentar hinterlassen

Was ist ein Zauberspruch überhaupt noch wert?

In Anbetracht der jüngsten Bestrebungen Odins, das Aufsagen von Zaubersprüchen gegen Geldzahlung noch weiter zu unterbinden, muss davon ausgegangen werden, dass Odin und die anderen Asen den Einfluss von Zaubersprüchen auf das finanzielle Wohlergehen des Besprochenen gegenüber dem Zustand von vor einigen Jahren um einen nicht unerheblichen Prozentsatz hoch- oder runtergeschraubt haben. Egal, wie man es dreht und wendet, ein Zauberspruch – sei er ein gekaufter, sei er den Zauberern über einen Trick der PR-Abteilung aufwändig abgetrotzt – kann in Durchschnitt gesehen nicht mehr genau den gleichen Einfluss auf den Geldregen über einen damit Gesegneten haben, den er zum Beispiel noch vor fünf Jahren hatte.

Weil wir in einem wortreichen Absatz halbwegs erfolgreich versucht haben, zu verbergen, dass wir vieles vermuten und dafür gar nichts wissen, wollen wir jetzt Scheinwissen durch eine Umfrage herstellen. Wir möchten herausbekommen, wie andere Zauberer den heutigen Einfluss des Reichtumsfaktors Zauberspruch einschätzen und deshalb um die Teilnahme an unserer kleinen Umfrage bitten. Wenn da ganz viele mitmachen und ihr völliges Unwissen über die Pläne und Absichten der Asen zu einem Umfrageergebnis zusammentragen, würden wir uns sehr darüber freuen.

Oder so ähnlich:mrgreen:

Veröffentlicht unter Technisches | Verschlagwortet mit , , , , | Kommentar hinterlassen

Ubuntu Annoyances, Teil 17391

Wer unter den vielen Freunden der Linux-Geschmacksrichtung »Ubuntu« 14.04 zurzeit feststellt, dass folgende Dinge nicht mehr gehen, obwohl sie in der früheren LTS-Version problemlos gingen…

…«darf« mal wieder selbst ein bisschen Hand anlegen. Keine Sorge, das tut diesmal nicht weh und sollte auch für Anfänger zu bewältigen sein.

Das Problem hat seine Ursache darin, dass der alte Displaymanager gdm inzwischen völlig aus der Ubuntu-Installation entfernt und durch lightdm ersetzt wurde. Dabei wurde auch gdmflexiserver aus der Standardinstallation entfernt, befindet sich aber weiterhin in der Konfiguration einiger Programme. Da Xscreensaver aus absurden Gründen¹ nicht weiter von Ubuntu unterstützt wird, ist das offenbar niemanden aufgefallen.

Natürlich ist es auch möglich, libgdm1 zu installieren, um dieses Problem zu fixen. Man kann eine Mücke auch mit einem Vorschlaghammer erschlagen und sich ganz nebenbei über die dabei angerichteten »Kollateralschäden« freuen. Das veraltete gdm-Paket kann leicht zu späteren Paketabhängigkeitsproblemen führen.

Besser ist die folgende Vorgehensweise, die allerdings den lightdm als verwendeten Displaymanager voraussetzt. Dieser ist Standard bei Ubuntu, Xubuntu, Lubuntu und wird bei Kubuntu anstelle des KDE-Displaymanagers KDM verwendet. Wer nicht von Hand einen anderen Displaymanager installiert hat, wird lightdm nutzen. Natürlich ist die folgende Vorgehensweise dennoch ohne Gewähr:

  1. Ein Terminalfenster aufmachen.
  2. Kommando: sudo touch /usr/local/bin/gdmflexiserver
    Dabei wird nach dem Passwort gefragt.
  3. Kommando: sudo chmod +x /usr/local/bin/gdmflexiserver
  4. Öffnen der Datei mit dem jeweiligen Lieblingseditor (zum Beispiel mit dem Kommando sudo editor /usr/local/bin/gdmflexiserver), um den folgenden Text einzufügen:
    #!/bin/sh
    dm-tool switch-to-greeter
    
  5. Fertig.

Eventuell ist es erforderlich, die Sitzung zu beenden und sich neu anzumelden, um den Erfolg auch zu sehen. Wer wissen möchte, was dm-tool tut und das Terminal noch offen hat, tippe mutigen Fingers man dm-tool.

Für Pedanten: Und nun der ganz korrekte Weg…

Natürlich war das ein schneller und etwas schmutziger Hack, der in dieser Form nur mit lightdm funktioniert. Wer diese Abhängigkeit von einem bestimmten Displaymanager nicht haben möchte, erledigt das über das »Monsterchen« namens dbus, so wie es unser aller Beglücker von freedesktop.org eigentlich vorgesehen haben, um uns allen die Freude an einem flexiblen und leicht verständlichen Betriebssystem zu verhageln.

Für die korrekte Vorgehensweise sind die folgenden Zeilen in die Datei /usr/local/bin/gdmflexiserver einzufügen – ich habe das übrigens nicht getestet, weil ich mir das Leben lieber leicht mache:

#!/bin/sh
test -z "$XDG_SEAT_PATH" && exit 1
dbus-send --system \
          --type=method_call \
          --print-reply \
          --dest=org.freedesktop.DisplayManager $XDG_SEAT_PATH \
                 org.freedesktop.DisplayManager.Seat.SwitchToGreeter

Nach dem Backslash \ darf kein Leerzeichen stehen, damit diese Zeilen von der Shell zu einer einzigen Zeile zusammengefasst werden… ich habe die Angewohnheit, längere Zeilen so aufzuteilen, dass ich sie möglichst leicht lesen kann.

¹Man muss nicht alles wegwerfen, nur weil es bewährt und weitgehend fehlerfrei ist, um seinen Anwendern stattdessen Strokelware mit schweren sicherheitskritischen Bugs zu installieren.

Veröffentlicht unter Technisches | Verschlagwortet mit , , , , , | Kommentar hinterlassen