ICEPortal analysiert

Wer häufiger mal ICE fährt, wird sicher das kostenfreie WLAN nutzen. Allerdings sind auch die Medien-Angebot der Bahn ganz nett, und mit entsprechenden "langen" Fahrzeiten auch gut nutzbar. Aber nichts ist schlimmer, als wenn man bei zu kurzen Fahrten eine Folge nicht zu Ende hören kann. Leider bietet die Bahn keinen einfachen Download oder zumindest Caching an. Es wäre doch mal nett, wenn es in der Bahn-App vergleichbar zu Spotify, Amazon oder auch der Arte Mediathek eine Option gäbe, eine Folge für eine begrenzte "Offline" zu erhalten. Daher habe ich mir angeschaut, wie die Webseite des ICEPortals im ICE-WLAN funktioniert.

Diese Seite ist keine Anleitung zum "Hacken" des ICE-Portals sondern soll einfach zur zeigen, wie Sie mit Windows-Bordmitteln des Browsers und PowerShell eine Webseite etwas genauer betrachten können. Alle Zugriffe auf dieser Seite sind anonym ohne Anmeldung möglich.

Seitenanalyse

Schon vor 30-40 Jahren, als es noch BTX gab, haben Softwareentwickler mit "ScreenScraping" arbeiten dürfen, d.h. eine Software tut so, als wäre sie ein Mensch und liest die Daten quasi aus dem Bildschirm ab. Das kann ein Anbieter natürlich verhindern, z.B. indem er ab und an eine Rückfrage (Captcha o.ä.) einbaut, die ein Skript nicht beantworten kann oder das Nutzerverhalten betrachtet. Wer viel mehr Daten herunterlädt, als er Wiedergeben kann, ist wohl ein "Downloader". Denkbar sind auch Bandbreitenlimits zum Abruf der Medien oder im Extremfall eine digitale Schutzfunktion (DRM), bei der ein Client immer mal wieder die "Berechtigung" in Form von Decryption-Keys  bei einem Server abrufen muss. Es gibt also durchaus mehr oder minder einfach umzusetzende Möglichkeiten einen Download zu verhindern.

Ich habe einfach mal die Bahn als Muster genommen, wie man mit einem einfachen Browser und PowerShell, d.h. ohne "Hackertools" sich eine Webseite genauer anschauen kann.

Ich bin bei der Fahrt im ICE von Frankfurt Flughafen über Köln nach Bielefeld am 17. März 2024 auf die Webseite "https://iceportal.de" der Bahn gegangen. Über die "DeveloperTools" (F12-Taste) habe ich das Laden der Seite betrachtet und sehr schnell erkannt, dass die Bahn eine "moderne" Seite bereitstellt, bei der nach dem Startseite mittels JavaScript die verschiedenen Elemente aus einer JSON-Datei ausgelesen, nachgeladen und angezeigt werden:

Status

Zuerst ist mit die "status"-URL aufgefallen.

Die Statusanzeige wird anonym als JSON-Antwort bereitgestellt und liefert durchaus interessante Werte:

 $status = Invoke-RestMethod https://iceportal.de/api1/rs/status
PS C:\> $status

connection   : True
serviceLevel : AVAILABLE_SERVICE
gpsStatus    : VALID
internet     : HIGH
latitude     : 51,2251461666667
longitude    : 7,05132533333333
tileY        : 136
tileX        : -183
series       : 803
serverTime   : 1710673120072
speed        : 57
trainType    : ICE
tzn          : ICE0153
wagonClass   : SECOND
connectivity : @{currentState=UNSTABLE; nextState=WEAK; remainingTimeSeconds=2400}
bapInstalled : True

PS C:\> $status.connectivity

currentState nextState remainingTimeSeconds
------------ --------- --------------------
UNSTABLE     WEAK                      2400

Die Position (Longitute, Lattitude) wird ca. alle 6 Sekunden aktualisiert.

Weitere URLs

Wenn Sie dann ihren Browser ohne weitere Eingaben "ruhen" lassen, dann lädt er dennoch immer wieder im Hintergrund entsprechende Updates nach. Neben dem Status des Zugs gibt es noch zwei weitere URLs:

{
  "bapServiceStatus" : "ACTIVE"
}

Wer mag, kann sich also eine eigene App zur Anzeige entwickeln. Allerdings macht das wenig Sinn, da die Daten ja nicht geheim sind und sowohl auf dem ICE-Portal selbst, der Bahn-App und im Internet erreichbaren API-Endpunkten der Bahn erreichbar sind.

Hörbücher

Mein Interesse galt nun den Hörbüchern. Über den Link "Hörbücher/Podcasts" hat mich "Arnold" angeschaut und einen Podcast mit 6h angezeigt.


Quelle https://iceportal.de/hoerbuecher

Sechs Stunden sind natürlich sehr viel und ob ich mir das wirklich antue, steht auf einem anderen Blatt. Aber bei 0:55 + 2:05h im ICE hätte ich eh nicht genug Zeit  Also schauen wir doch mal, was die Bahn hier macht.

Die "Hoerbuecher"-URL fällt direkt ohne längeres Suchen auf:

Die Antwort ist eine JSON-Struktur, die einen ersten Rückschluss auf die Hörbücher zulässt.

Wenn ich dann ein Hörbuch anklicke, dann sehe ich einen Abruf über die in "href" angegeben URL:

Die gelieferte JSON-Datei enthält alles, was die Folgen ausmacht. (gekürzt)

{
    "type": "ContentPage",
    "contentType": "audioBook",
    "title": "Be Useful",
    "subtitle": "Biografie",
    "picture": {
        "alt": "Be Useful",
        "src": "img-audiobooks/34-000000001326/9783754011034.jpg",
        "copyRight": null,
    },
    "subject": "Mehr denn je brauchen Menschen heute Hoffnung. Sie brauchen Träume und Vorbilder, .....",
    "copyRights": [],
    "metaInfos": [],
    "text": null,
    "genre": null,
    "duration": "PT6H32M37S",
    "author": "Arnold Schwarzenegger",
    "speaker": "Bernd Egger",
    "offerPeriod": "Dieses Hörbuch können Sie noch bis zum 31.03.2024 im ICE Portal hören.",
    "publisher": "2023 Bastei Lübbe AG",
    "releaseYear": "2023",
    "files": [
        {
            "serialNumber": 1,
            "title": "Be Useful, Kapitel 1",
            "path": "/aod-audiobooks/34-000000001326/9783754011034_001.m4a",
            "countPath": "audiobooks/ab/34-000000001326/1",
            "duration": 18,
            "length": 0,
            "mimeType": "audio/mp4",
        },
        {
            "serialNumber": 2,
            "title": "Be Useful, Kapitel 2",
            "path": "/aod-audiobooks/34-000000001326/9783754011034_002.m4a",
            "countPath": "audiobooks/ab/34-000000001326/2",
            "duration": 202,
            "length": 0,
            "mimeType": "audio/mp4",
        },

Eigentlich haben wir damit als Entwickler schon alles zusammen, um alle Folgen herunterzuladen.

$URL = "http://iceportal.de/"

# Liste der Hoerbuecher abrufen
$hoerbuecher=Invoke-RestMethod "$($URL)api1/rs/page/hoerbuecher"

# Titel ausgeben
$hoerbuecher.teaserGroups.items.title |ft

ForEach ($hoerbuch in $hoerbuecher.teaserGroups.items) {
   Write-Host "Processing $($hoerbuch.title)"
   # Details mit Bild und File laden
   $hoerbuchdetails = Invoke-RestMethod `
                       -Uri "$($URL)api1/rs/page/$($hoerbuch.navigation.href)" 

   # Zielverzeichnis festlegen und ungültige Zeichen entfernen
   $targetdir = "./" + ("$($hoerbuch.title)".Split([IO.Path]::GetInvalidFileNameChars()) -join '_') 
   #Bild herunterladen
   Invoke-WebRequest `
      -Uri "$($URL)$($hoerbuchdetails.picture.src)" `
      -Outfile "$($targetdir)/image.jpg"

   # Download der Medien
   foreach ($mediafile in $hoerbuchdetails.files){
      Write-host "Title $($mediafile.title)"
      Write-host "MediaSource $($mediafile.path)"
      $Extension = $mediafile.path.split(".")[-1]
      Write-host "Extension $($extension)"
      $targetfile = "$($mediafile.title).$Extension".Split([IO.Path]::GetInvalidFileNameChars()) -join '_'
      Invoke-Webrequest `
         -uri "$($URL)$($mediafile.path)" `
         -outfile "$($targetdir)/$targetfile"
   }
   Write-host "Download-Picture: $($hoerbuch.picture.src)"
}

Damit hätte ich dann alle Dateien in einzelnen Folgen. Fertig sind wir damit aber noch nicht.:

  • Passende Nummerierung
    Die Dateinaben sind nicht immer passend und "Folge1, Folge2,...Folge9, Folge10, Folge11" sortiert sich nicht passend, wenn ich ein "01, 02,03" als Nummerierung verwendet
  • m4a-Dateien zusammenführen
    Verschiedene Folgen sind doch "arg kurz" und wenn ich mal einen Weg finde, einfach mehrere Audio-Dateien in der richtigen Reihenfolge automatisch aneinander zu kleben, dann wäre das eine mögliche Weiterentwicklung. Manuell geht es natürlich z.B. per VLCPlayer, Audacity
  • XML zum Abspielen (M3U-Datei)
    Andererseits gibt es ja auch "Playlist"-Dateien, in der ich alle Folgen samt Beschreibung referenzieren und dann einfach per Mediaplayer wiedergeben kann. Dann könnte ich die Dateien als einzelne Kapitel lassen aber eine Playlist für die elegante Wiedergabe bereitstellen.
  • Mehrfach-Download
    Das Angebot der Bahn ändert sich immer mal wieder aber leider lädt "Invoke-Webrequest" anscheinend die Dateien immer wieder herunter. Man sollte schon vorher prüfen, ob die Datei schon vorhanden ist, um Mehrfachdownloads zu verhindern. Dann muss man aber auch abgebrochene Downloads behandeln.

Das Skript ist also mehr ein Sample denn eine fertige Lösung

Zeitschriften und Videos

Genauso könnten Sie nun natürlich auch die anderen Inhalte, d.h. Videos, Zeitschriften etc. über eine Analyse der HTTPS-Request im Browser-Debugger ermitteln und die Dateien zur späteren Betrachtung herunterladen. Die URL ist

https://iceportal.de/api1/rs/page/zeitungskiosk

Eine URL eines Abschnittes des "Der Schwarm" war z.B.

https://assets.filme-serien.iceportal.de/contents/media/videos/der-schwarm-s01e01/t/dash_vp9/aud_64_de.m4s

Das habe ich aber nicht weiter umgesetzt, denn letztlich muss man ja auch die Zeit haben, die so erhaltenen Medien auch einmal zu lesen. Und nichts ist älter als die Tageszeitung von gestern oder Wochenzeitschrift der Vorwoche. Das ist ja gerade der große Vorteil beim Fahren mit dem Zug gegenüber dem eigenen Auto oder dem mehr oder weniger hektischen Flügen: Sie haben einige Stunden am Stück "Zeit".

Bemerkung

Beachten Sie, dass die Nutzung des Bahn-Angebots vermutlich auf Mitfahrer im ICE beschränkt ist und die DB dürfte daher keine Lizenz zum Download der Medien haben. Es dürfte daher nicht im Interesse der Bahn und schon gar nicht im Interesse der Rechteinhaber sein, wenn Sie über solche Skripte die Inhalte offline auf ihren Notebook übertragen und diese auch ohne Verbindung zum ICE-Portal weiter konsumieren.

Diese Beschreibung und Skripte sind aber keine "Hackertools", denn es wird an keiner Stelle versucht eine Sicherheitslücke auszunutzen oder besonders geschützte Schnittstellen anzusprechen. Ganz im Gegenteil. Sie könnten auch problemlos alle Zeitschriften in mehreren BrowserTabs anschauen und manuell herunterladen und wenn ihr Browser die Media-Dateien nicht direkt wiedergeben kann, dann können Sie auch diese herunterladen oder aus dem Browser-Cache herausfischen.

Ich habe weder bei Audio noch Video erkennen können, dass seitens des ICE-Portal hier eine Drosselung durchgeführt wird. Technisch wäre es einfach möglich, die übertragene Datenmenge pro Client entsprechend zu limitieren. Dies findet aber anscheinend nicht statt.

Weitere Links