From 6160d2b6b5fe27fffead008630d919b1697d7a08 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 24 Feb 2025 01:53:19 +0100 Subject: [PATCH 01/14] playsuisse.py: handle locale parameters from URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Currently, the locale header is statically set to “de”, regardless of which locale is set in the URL parameters. - Therefore, all retrieved metadata (description, names, etc.) were in German. - This PR implements a mechanism that extracts the locale value from the specified URL. - As a fallback, URLs without locale parameters are automatically set to de, which corresponds to the original behavior. Advantages: All metadata is retrieved in the specified language. --- yt_dlp/extractor/playsuisse.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 59231d8405..20e2e7950d 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -214,27 +214,16 @@ class PlaySuisseIE(InfoExtractor): if not self._ID_TOKEN: raise ExtractorError('Login failed') - - def _get_media_data(self, media_id): - # NOTE In the web app, the "locale" header is used to switch between languages, - # However this doesn't seem to take effect when passing the header here. - response = self._download_json( - 'https://www.playsuisse.ch/api/graphql', - media_id, data=json.dumps({ - 'operationName': 'AssetWatch', - 'query': self._GRAPHQL_QUERY, - 'variables': {'assetId': media_id}, - }).encode(), - headers={'Content-Type': 'application/json', 'locale': 'de'}) - - return response['data']['assetV2'] - + def _real_extract(self, url): if not self._ID_TOKEN: self.raise_login_required(method='password') - + media_id = self._match_id(url) - media_data = self._get_media_data(media_id) + query = parse_qs(url) + locale_param = (query.get('locale') or ['de'])[0].lower() + locale = locale_param if locale_param in {'fr', 'en', 'it', 'de', 'rm'} else 'de' + media_data = self._get_media_data(media_id, locale) info = self._extract_single(media_data) if media_data.get('episodes'): info.update({ @@ -242,6 +231,17 @@ class PlaySuisseIE(InfoExtractor): 'entries': map(self._extract_single, media_data['episodes']), }) return info + + def _get_media_data(self, media_id, locale): + response = self._download_json( + 'https://www.playsuisse.ch/api/graphql', + media_id, data=json.dumps({ + 'operationName': 'AssetWatch', + 'query': self._GRAPHQL_QUERY, + 'variables': {'assetId': media_id}, + }).encode(), + headers={'Content-Type': 'application/json', 'locale': locale}) + return response['data']['assetV2'] def _extract_single(self, media_data): thumbnails = traverse_obj(media_data, lambda k, _: k.startswith('thumbnail')) From 50b35cab6dc6a3bb3a06f06a77676514fe7f80b0 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 24 Feb 2025 02:07:35 +0100 Subject: [PATCH 02/14] fix whitespaces --- yt_dlp/extractor/playsuisse.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 20e2e7950d..3e39a467eb 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -214,11 +214,11 @@ class PlaySuisseIE(InfoExtractor): if not self._ID_TOKEN: raise ExtractorError('Login failed') - + def _real_extract(self, url): if not self._ID_TOKEN: self.raise_login_required(method='password') - + media_id = self._match_id(url) query = parse_qs(url) locale_param = (query.get('locale') or ['de'])[0].lower() @@ -231,7 +231,7 @@ class PlaySuisseIE(InfoExtractor): 'entries': map(self._extract_single, media_data['episodes']), }) return info - + def _get_media_data(self, media_id, locale): response = self._download_json( 'https://www.playsuisse.ch/api/graphql', From ee565d9c327e2ea6cedb76abfcac28979c3a8ac6 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:11:05 +0100 Subject: [PATCH 03/14] add more values --- yt_dlp/extractor/playsuisse.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 3e39a467eb..6109052dc6 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -7,6 +7,7 @@ from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, + str_or_none, parse_qs, traverse_obj, update_url_query, @@ -120,6 +121,16 @@ class PlaySuisseIE(InfoExtractor): id name description + descriptionLong + year + contentTypes + countries + composers + directors + writers + mainCast + productionCompanies + productionCountries duration episodeNumber seasonNumber @@ -259,7 +270,12 @@ class PlaySuisseIE(InfoExtractor): return { 'id': media_data['id'], 'title': media_data.get('name'), - 'description': media_data.get('description'), + 'description': media_data.get('descriptionLong') or media_data.get('description'), + 'genres': media_data.get('contentTypes'), + 'creators': media_data.get('directors'), + 'cast': media_data.get('mainCast'), + 'location': media_data.get('productionCountries'), + 'release_year': int_or_none(media_data.get('year')[:4]) if media_data.get('year') else None , 'thumbnails': thumbnails, 'duration': int_or_none(media_data.get('duration')), 'formats': formats, From 7282b3fe8b6716dd6cda2d4885cd45360a9b1deb Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:12:34 +0100 Subject: [PATCH 04/14] remove unused str_or_none --- yt_dlp/extractor/playsuisse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 6109052dc6..7fff24ec18 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -7,7 +7,6 @@ from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, - str_or_none, parse_qs, traverse_obj, update_url_query, From d41aa41408520a1b1f6315058c193f1233e50748 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:16:59 +0100 Subject: [PATCH 05/14] typo --- yt_dlp/extractor/playsuisse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 7fff24ec18..5e36908bb3 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -274,7 +274,7 @@ class PlaySuisseIE(InfoExtractor): 'creators': media_data.get('directors'), 'cast': media_data.get('mainCast'), 'location': media_data.get('productionCountries'), - 'release_year': int_or_none(media_data.get('year')[:4]) if media_data.get('year') else None , + 'release_year': int_or_none(media_data.get('year')[:4]) if media_data.get('year') else None, 'thumbnails': thumbnails, 'duration': int_or_none(media_data.get('duration')), 'formats': formats, From 4c8e7e7b6d028621b2e8905e833a8e41f5c5a910 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:20:06 +0100 Subject: [PATCH 06/14] remove not supported "en" locale variable --- yt_dlp/extractor/playsuisse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 5e36908bb3..a431d85292 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -232,7 +232,7 @@ class PlaySuisseIE(InfoExtractor): media_id = self._match_id(url) query = parse_qs(url) locale_param = (query.get('locale') or ['de'])[0].lower() - locale = locale_param if locale_param in {'fr', 'en', 'it', 'de', 'rm'} else 'de' + locale = locale_param if locale_param in {'de', 'fr', 'it', 'rm'} else 'de' media_data = self._get_media_data(media_id, locale) info = self._extract_single(media_data) if media_data.get('episodes'): From 53c12e82021db45c7e0715f0b958a8221873ea94 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 3 Mar 2025 23:48:28 +0100 Subject: [PATCH 07/14] fix moving method around --- yt_dlp/extractor/playsuisse.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index a431d85292..e54f51251f 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -225,6 +225,17 @@ class PlaySuisseIE(InfoExtractor): if not self._ID_TOKEN: raise ExtractorError('Login failed') + def _get_media_data(self, media_id, locale): + response = self._download_json( + 'https://www.playsuisse.ch/api/graphql', + media_id, data=json.dumps({ + 'operationName': 'AssetWatch', + 'query': self._GRAPHQL_QUERY, + 'variables': {'assetId': media_id}, + }).encode(), + headers={'Content-Type': 'application/json', 'locale': locale}) + return response['data']['assetV2'] + def _real_extract(self, url): if not self._ID_TOKEN: self.raise_login_required(method='password') @@ -242,17 +253,6 @@ class PlaySuisseIE(InfoExtractor): }) return info - def _get_media_data(self, media_id, locale): - response = self._download_json( - 'https://www.playsuisse.ch/api/graphql', - media_id, data=json.dumps({ - 'operationName': 'AssetWatch', - 'query': self._GRAPHQL_QUERY, - 'variables': {'assetId': media_id}, - }).encode(), - headers={'Content-Type': 'application/json', 'locale': locale}) - return response['data']['assetV2'] - def _extract_single(self, media_data): thumbnails = traverse_obj(media_data, lambda k, _: k.startswith('thumbnail')) From df83969f0b8a88554fb8a0dc252f28914153e448 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 3 Mar 2025 23:49:37 +0100 Subject: [PATCH 08/14] fix space --- yt_dlp/extractor/playsuisse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index e54f51251f..4a4f768b1c 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -235,7 +235,7 @@ class PlaySuisseIE(InfoExtractor): }).encode(), headers={'Content-Type': 'application/json', 'locale': locale}) return response['data']['assetV2'] - + def _real_extract(self, url): if not self._ID_TOKEN: self.raise_login_required(method='password') From fc6233c5d13907ebfac0707a47dd85e33667c592 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 3 Mar 2025 23:52:44 +0100 Subject: [PATCH 09/14] remove unused graphql queries Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com> --- yt_dlp/extractor/playsuisse.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 4a4f768b1c..96c3048c59 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -123,12 +123,8 @@ class PlaySuisseIE(InfoExtractor): descriptionLong year contentTypes - countries - composers directors - writers mainCast - productionCompanies productionCountries duration episodeNumber From 254f8376c2f9e810cfb4a1e1d54e11b426febd63 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 3 Mar 2025 23:54:31 +0100 Subject: [PATCH 10/14] adjust media_data Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com> --- yt_dlp/extractor/playsuisse.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 96c3048c59..cd6196c866 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -237,10 +237,7 @@ class PlaySuisseIE(InfoExtractor): self.raise_login_required(method='password') media_id = self._match_id(url) - query = parse_qs(url) - locale_param = (query.get('locale') or ['de'])[0].lower() - locale = locale_param if locale_param in {'de', 'fr', 'it', 'rm'} else 'de' - media_data = self._get_media_data(media_id, locale) + media_data = self._get_media_data(media_id, traverse_obj(parse_qs(url), ('locale', '0'), default='de')) info = self._extract_single(media_data) if media_data.get('episodes'): info.update({ From def349faf6a4a9ec37ddea87d4f0a5b247a3577c Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Wed, 5 Mar 2025 12:54:41 +0100 Subject: [PATCH 11/14] traverse_obj rewrite --- yt_dlp/extractor/playsuisse.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index cd6196c866..57ba82e7da 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -260,20 +260,21 @@ class PlaySuisseIE(InfoExtractor): self._merge_subtitles(subs, target=subtitles) return { - 'id': media_data['id'], - 'title': media_data.get('name'), - 'description': media_data.get('descriptionLong') or media_data.get('description'), - 'genres': media_data.get('contentTypes'), - 'creators': media_data.get('directors'), - 'cast': media_data.get('mainCast'), - 'location': media_data.get('productionCountries'), - 'release_year': int_or_none(media_data.get('year')[:4]) if media_data.get('year') else None, + 'id': traverse_obj(media_data, 'id'), + 'title': traverse_obj(media_data, 'name'), + 'description': traverse_obj(media_data, 'descriptionLong') or traverse_obj(media_data, 'description'), + 'genres': traverse_obj(media_data, 'contentTypes'), + 'creators': traverse_obj(media_data, 'directors'), + 'cast': traverse_obj(media_data, 'mainCast'), + 'location': traverse_obj(media_data, 'productionCountries'), + 'release_year': int_or_none(traverse_obj(media_data, 'year', lambda x: x[:4])), 'thumbnails': thumbnails, - 'duration': int_or_none(media_data.get('duration')), + 'duration': int_or_none(traverse_obj(media_data, 'duration')), 'formats': formats, 'subtitles': subtitles, - 'series': media_data.get('seriesName'), - 'season_number': int_or_none(media_data.get('seasonNumber')), - 'episode': media_data.get('name') if media_data.get('episodeNumber') else None, - 'episode_number': int_or_none(media_data.get('episodeNumber')), + 'series': traverse_obj(media_data, 'seriesName'), + 'season_number': int_or_none(traverse_obj(media_data, 'seasonNumber')), + 'episode': traverse_obj(media_data, 'name') if traverse_obj(media_data, 'episodeNumber') else None, + 'episode_number': int_or_none(traverse_obj(media_data, 'episodeNumber')), } + From ac548098377946d1424818e3a314dce99081c165 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Wed, 5 Mar 2025 12:59:12 +0100 Subject: [PATCH 12/14] fix typos --- yt_dlp/extractor/playsuisse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index 57ba82e7da..dd67ac7bdf 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -277,4 +277,3 @@ class PlaySuisseIE(InfoExtractor): 'episode': traverse_obj(media_data, 'name') if traverse_obj(media_data, 'episodeNumber') else None, 'episode_number': int_or_none(traverse_obj(media_data, 'episodeNumber')), } - From 291ea778c393c0f3c646c32f10d16ae0ced63a6a Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:49:30 +0100 Subject: [PATCH 13/14] revert 'self._get_media_data' changes The language specific metadata extraction was broken with these changes, had to revert them in order to get language specific metadata extraction into a working condition again. --- yt_dlp/extractor/playsuisse.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index dd67ac7bdf..c9bc30e75e 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -237,7 +237,10 @@ class PlaySuisseIE(InfoExtractor): self.raise_login_required(method='password') media_id = self._match_id(url) - media_data = self._get_media_data(media_id, traverse_obj(parse_qs(url), ('locale', '0'), default='de')) + query = parse_qs(url) + locale_param = (query.get('locale') or ['de'])[0].lower() + locale = locale_param if locale_param in {'de', 'fr', 'it', 'rm'} else 'de' + media_data = self._get_media_data(media_id, locale) info = self._extract_single(media_data) if media_data.get('episodes'): info.update({ @@ -267,7 +270,7 @@ class PlaySuisseIE(InfoExtractor): 'creators': traverse_obj(media_data, 'directors'), 'cast': traverse_obj(media_data, 'mainCast'), 'location': traverse_obj(media_data, 'productionCountries'), - 'release_year': int_or_none(traverse_obj(media_data, 'year', lambda x: x[:4])), + 'release_year': int_or_none(traverse_obj(media_data, 'year', lambda _, x: x[:4])), 'thumbnails': thumbnails, 'duration': int_or_none(traverse_obj(media_data, 'duration')), 'formats': formats, From 6fead90fd3f6fdc0d9f691d8c2dacef72bbe5666 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Tue, 11 Mar 2025 12:30:20 +0100 Subject: [PATCH 14/14] Update yt_dlp/extractor/playsuisse.py Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com> --- yt_dlp/extractor/playsuisse.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yt_dlp/extractor/playsuisse.py b/yt_dlp/extractor/playsuisse.py index c9bc30e75e..d74024b03a 100644 --- a/yt_dlp/extractor/playsuisse.py +++ b/yt_dlp/extractor/playsuisse.py @@ -237,10 +237,7 @@ class PlaySuisseIE(InfoExtractor): self.raise_login_required(method='password') media_id = self._match_id(url) - query = parse_qs(url) - locale_param = (query.get('locale') or ['de'])[0].lower() - locale = locale_param if locale_param in {'de', 'fr', 'it', 'rm'} else 'de' - media_data = self._get_media_data(media_id, locale) + media_data = self._get_media_data(media_id, traverse_obj(parse_qs(url), ('locale', 0), default='de')) info = self._extract_single(media_data) if media_data.get('episodes'): info.update({