Skip to content

plugins.sportschau: fix sportschau #6104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 2, 2024

Conversation

gsilvan
Copy link
Contributor

@gsilvan gsilvan commented Aug 1, 2024

The current plugin for sportschau.de is not working.

Example: https://www.sportschau.de/olympia/sportschiessen-luftpistole-10m-mixed-im-re-live,video-olympia-sportschiessen-104.html

streamlink https://www.sportschau.de/olympia/sportschiessen-luftpistole-10m-mixed-im-re-live,video-olympia-sportschiessen-104.html
[cli][info] Found matching plugin sportschau for URL https://www.sportschau.de/olympia/sportschiessen-luftpistole-10m-mixed-im-re-live,video-olympia-sportschiessen-104.html
error: No playable streams found on this URL: https://www.sportschau.de/olympia/sportschiessen-luftpistole-10m-mixed-im-re-live,video-olympia-sportschiessen-104.html

This PR fixes it.

Copy link
Member

@bastimeyer bastimeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, but I'm afraid the plugin can't be (fully) fixed right now. Not because of the data extraction, but because of the HLS streams, which include packed audio streams, which is still unsupported by Streamlink. ARD Mediathek for example suffers from the same issue. See #4721.

The only workaround right now is using the --stream-url option without selecting a specific stream, so that the HLS multivariant playlist URL is returned, which can then be used as the player's launch argument, if the player does support HLS playlist inputs. --player-passthrough=hls does not work with multivariant playlist (which I just noticed).

mpv "$(streamlink sportschau.de --stream-url)"

Apart from that, there's some room for improvements here. The validation schema is not validating anything, which it really should, or else ugly errors will be raised by the plugin when there's an issue with the expected data, and metadata is also missing. The HTTPStream VODs are also unneeded, as the same content is always available via HLS (without packed audio streams).

The following diff would fix that (I don't want to add multiple review comments for this, because it's unnecessarily confusing and a waste of time):

diff --git a/src/streamlink/plugins/sportschau.py b/src/streamlink/plugins/sportschau.py
index fce34ac7..9eb124a8 100644
--- a/src/streamlink/plugins/sportschau.py
+++ b/src/streamlink/plugins/sportschau.py
@@ -1,7 +1,9 @@
 """
-$description German sports magazine live stream, owned by ARD.
+$description German sports magazine live streams and VOD content, owned by ARD.
 $url sportschau.de
 $type live
+$metadata id
+$metadata title
 """
 
 import logging
@@ -10,38 +12,65 @@ import re
 from streamlink.plugin import Plugin, pluginmatcher
 from streamlink.plugin.api import validate
 from streamlink.stream.hls import HLSStream
-from streamlink.stream.http import HTTPStream
+
 
 log = logging.getLogger(__name__)
 
 
-@pluginmatcher(
-    re.compile(
-        r"https?://(?:\w+\.)*sportschau\.de/",
-    )
-)
+@pluginmatcher(re.compile(r"https?://(?:\w+\.)*sportschau\.de/"))
 class Sportschau(Plugin):
-    def _get_streams(self):
-        streams = self.session.http.get(
-            self.url,
-            schema=validate.Schema(
-                validate.parse_html(),
-                validate.xml_xpath_string("(//*[@data-v-type='MediaPlayer'])[1]/@data-v"),
-                validate.parse_json(),
-                validate.get("mc"),
-                validate.get("streams"),
+    _schema_media = validate.Schema(
+        validate.parse_html(),
+        validate.xml_xpath_string(".//*[@data-v-type='MediaPlayer'][@data-v][1]/@data-v"),
+        validate.none_or_all(
+            validate.parse_json(),
+            {
+                "mc": {
+                    validate.optional("id"): str,
+                    "meta": {
+                        "title": str,
+                    },
+                    "streams": [
+                        validate.all(
+                            {
+                                "media": [
+                                    validate.all(
+                                        {
+                                            "mimeType": str,
+                                            "url": validate.url(),
+                                        },
+                                        validate.union_get(
+                                            "mimeType",
+                                            "url",
+                                        ),
+                                    ),
+                                ],
+                            },
+                            validate.get("media"),
+                        ),
+                    ],
+                },
+            },
+            validate.get("mc"),
+            validate.union_get(
+                "id",
+                ("meta", "title"),
+                "streams",
             ),
-        )
-        for stream in streams:
-            for media in stream.get("media"):
-                url = media.get("url")
-                is_hls = media.get("mimeType") == "application/vnd.apple.mpegurl"
-                is_audio_only = stream.get("isAudioOnly")
-                if is_hls:
+        ),
+    )
+
+    def _get_streams(self):
+        data = self.session.http.get(self.url, schema=self._schema_media)
+        if not data:
+            return
+
+        self.id, self.title, streams = data
+
+        for media in streams:
+            for mime_type, url in media:
+                if mime_type == "application/vnd.apple.mpegurl":
                     yield from HLSStream.parse_variant_playlist(self.session, url).items()
-                else:
-                    media_type = "audio" if is_audio_only else "video"
-                    yield media_type, HTTPStream(self.session, url)
 
 
 __plugin__ = Sportschau
diff --git a/tests/plugins/test_sportschau.py b/tests/plugins/test_sportschau.py
index 235159e5..dcbcaa6b 100644
--- a/tests/plugins/test_sportschau.py
+++ b/tests/plugins/test_sportschau.py
@@ -6,6 +6,6 @@ class TestPluginCanHandleUrlSportschau(PluginCanHandleUrl):
     __plugin__ = Sportschau
 
     should_match = [
-        "http://www.sportschau.de/wintersport/videostream-livestream---wintersport-im-ersten-242.html",
-        "https://www.sportschau.de/weitere/allgemein/video-kite-surf-world-tour-100.html",
+        "https://www.sportschau.de/fussball/uefa-euro-2024/spaniens-europameister-begeistert-empfangen,em-spanien-feier-100.html",
+        "https://www.sportschau.de/olympia/live/schwimmen-finals-m-f,livestream-olympia-schwimmen-110.html",
     ]
$ ./script/test-plugin-urls.py sportschau -m
:: https://www.sportschau.de/fussball/uefa-euro-2024/spaniens-europameister-begeistert-empfangen,em-spanien-feier-100.html
::  270p, 360p, 540p, 720p, 1080p, worst, best
::   {'id': None, 'author': None, 'category': None, 'title': 'Nach Finalsieg in Berlin: Spaniens Europameister werden empfangen'}
:: https://www.sportschau.de/olympia/live/schwimmen-finals-m-f,livestream-olympia-schwimmen-110.html
::  270p, 360p, 540p, 720p, 1080p, worst, best
::   {'id': 'paris-2024-ecms-epg-1940-livestream', 'author': None, 'category': None, 'title': 'Olympia live - Schwimmen: Finals (M, F)'}

@bastimeyer bastimeyer added plugin issue A Plugin does not work correctly stream: HLS labels Aug 1, 2024
@gsilvan
Copy link
Contributor Author

gsilvan commented Aug 1, 2024

Thanks for your review!

Applied your patch, but i left the HTTPStream in for the sake of audio-on-demand and icecast-live.

Examples:

Couldn't find a HLS for those yet. Any thoughts on that?

gsilvan and others added 2 commits August 2, 2024 12:27
Co-authored-by: Sebastian Meyer <mail@bastimeyer.de>
Co-authored-by: Sebastian Meyer <mail@bastimeyer.de>
@bastimeyer
Copy link
Member

Thanks. Should be fine now. Well, apart from the HLS packed audio situation of course which will require the --stream-url workaround.

$ ./script/test-plugin-urls.py sportschau -m
:: https://www.sportschau.de/fussball/uefa-euro-2024/spaniens-europameister-begeistert-empfangen,em-spanien-feier-100.html
::  270p, 360p, 540p, 720p, 1080p, worst, best
::   {'id': None, 'author': None, 'category': None, 'title': 'Nach Finalsieg in Berlin: Spaniens Europameister werden empfangen'}
:: https://www.sportschau.de/olympia/live/schwimmen-finals-m-f,livestream-olympia-schwimmen-110.html
::  270p, 360p, 540p, 720p, 1080p, worst, best
::   {'id': None, 'author': None, 'category': None, 'title': 'Olympia 2024 - Schwimmen: Finals (M, F) im Re-Live'}
:: https://www.sportschau.de/podcasts/sportschau-olympia-podcast/tag-6-vier-gewinnt,audio-tag-6-vier-gewinnt-100.html
::  audio, worst, best
::   {'id': None, 'author': None, 'category': None, 'title': 'Der Sportschau-Olympia-Podcast: Tag 6 - Vier gewinnt'}

For the record, pages without media content are also working correctly:

$ streamlink https://www.sportschau.de/olympia/kroppen-unruh-kaempfen-sich-ins-viertelfinale,olympia-paris-bogenschiessen-mixed-team-100.html
[cli][info] Found matching plugin sportschau for URL https://www.sportschau.de/olympia/kroppen-unruh-kaempfen-sich-ins-viertelfinale,olympia-paris-bogenschiessen-mixed-team-100.html
error: No playable streams found on this URL: https://www.sportschau.de/olympia/kroppen-unruh-kaempfen-sich-ins-viertelfinale,olympia-paris-bogenschiessen-mixed-team-100.html

@bastimeyer bastimeyer merged commit e502494 into streamlink:master Aug 2, 2024
23 checks passed
@gsilvan
Copy link
Contributor Author

gsilvan commented Aug 2, 2024

Thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin issue A Plugin does not work correctly stream: HLS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants