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:
-
https://iceportal.de/bap/api/bap-service-status
Liefert mir nur eine JSON-Datei ohne
{ "bapServiceStatus" : "ACTIVE" }
-
https://iceportal.de/api1/rs/tripInfo/trip
Diese URL liefert eine ausführliche Information über den Zug aber auch alle Zwischenhalte samt geplanter Zeiten und anscheinend Anschlusszüge.
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
- ICE Portal: Immer bestens informiert & gut unterhalten
https://www.bahn.de/service/zug/ice-portal - iceportal-downloader
https://github.com/alexanderadam/ice_portal_downloader - xflr6/iceportal.py
https://gist.github.com/xflr6/759737dc06b290a009352d3307782a2b