Compare commits

...

7 Commits

Author SHA1 Message Date
s-tdh
3991e08176
Merge 00f0acfade into b83ca24eb7 2024-11-10 09:19:38 +05:30
sepro
b83ca24eb7
[core] Catch broken Cryptodome installations (#11486)
Authored by: seproDev
2024-11-10 00:53:49 +01:00
bashonly
240a7d43c8
[build] Pin websockets version to >=13.0,<14 (#11488)
websockets 14.0 causes CI test failures (a lot more of them)

Authored by: bashonly
2024-11-09 23:46:47 +00:00
bashonly
f13df591d4
[build] Enable attestations for trusted publishing (#11420)
Reverts 428ffb75aa

Authored by: bashonly
2024-11-09 23:26:02 +00:00
stdh
00f0acfade [ie/vrt] Ruff errors: third time's the charm? 2024-08-02 00:05:03 +02:00
stdh
1433b22da5 [ie/vrt] (Hopefully) fix ruff errors 2024-08-01 21:20:46 +02:00
stdh
ddeec34393 [ie/vrt] Add support for radio shows 2024-08-01 19:28:34 +02:00
8 changed files with 175 additions and 8 deletions

View File

@ -504,7 +504,8 @@ jobs:
- windows32 - windows32
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/download-artifact@v4 - name: Download artifacts
uses: actions/download-artifact@v4
with: with:
path: artifact path: artifact
pattern: build-bin-* pattern: build-bin-*

View File

@ -28,3 +28,20 @@ jobs:
actions: write # For cleaning up cache actions: write # For cleaning up cache
id-token: write # mandatory for trusted publishing id-token: write # mandatory for trusted publishing
secrets: inherit secrets: inherit
publish_pypi:
needs: [release]
if: vars.MASTER_PYPI_PROJECT != ''
runs-on: ubuntu-latest
permissions:
id-token: write # mandatory for trusted publishing
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
name: build-pypi
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true

View File

@ -41,3 +41,20 @@ jobs:
actions: write # For cleaning up cache actions: write # For cleaning up cache
id-token: write # mandatory for trusted publishing id-token: write # mandatory for trusted publishing
secrets: inherit secrets: inherit
publish_pypi:
needs: [release]
if: vars.NIGHTLY_PYPI_PROJECT != ''
runs-on: ubuntu-latest
permissions:
id-token: write # mandatory for trusted publishing
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
name: build-pypi
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true

View File

@ -2,10 +2,6 @@ name: Release
on: on:
workflow_call: workflow_call:
inputs: inputs:
prerelease:
required: false
default: true
type: boolean
source: source:
required: false required: false
default: '' default: ''
@ -18,6 +14,10 @@ on:
required: false required: false
default: '' default: ''
type: string type: string
prerelease:
required: false
default: true
type: boolean
workflow_dispatch: workflow_dispatch:
inputs: inputs:
source: source:
@ -278,11 +278,20 @@ jobs:
make clean-cache make clean-cache
python -m build --no-isolation . python -m build --no-isolation .
- name: Upload artifacts
if: github.event_name != 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: build-pypi
path: |
dist/*
compression-level: 0
- name: Publish to PyPI - name: Publish to PyPI
if: github.event_name == 'workflow_dispatch'
uses: pypa/gh-action-pypi-publish@release/v1 uses: pypa/gh-action-pypi-publish@release/v1
with: with:
verbose: true verbose: true
attestations: false # Currently doesn't work w/ reusable workflows (breaks nightly)
publish: publish:
needs: [prepare, build] needs: [prepare, build]

View File

@ -52,7 +52,7 @@ default = [
"pycryptodomex", "pycryptodomex",
"requests>=2.32.2,<3", "requests>=2.32.2,<3",
"urllib3>=1.26.17,<3", "urllib3>=1.26.17,<3",
"websockets>=13.0", "websockets>=13.0,<14",
] ]
curl-cffi = [ curl-cffi = [
"curl-cffi==0.5.10; os_name=='nt' and implementation_name=='cpython'", "curl-cffi==0.5.10; os_name=='nt' and implementation_name=='cpython'",

View File

@ -24,7 +24,7 @@ try:
from Crypto.Cipher import AES, PKCS1_OAEP, Blowfish, PKCS1_v1_5 # noqa: F401 from Crypto.Cipher import AES, PKCS1_OAEP, Blowfish, PKCS1_v1_5 # noqa: F401
from Crypto.Hash import CMAC, SHA1 # noqa: F401 from Crypto.Hash import CMAC, SHA1 # noqa: F401
from Crypto.PublicKey import RSA # noqa: F401 from Crypto.PublicKey import RSA # noqa: F401
except ImportError: except (ImportError, OSError):
__version__ = f'broken {__version__}'.strip() __version__ = f'broken {__version__}'.strip()

View File

@ -2392,6 +2392,7 @@ from .vrt import (
DagelijkseKostIE, DagelijkseKostIE,
KetnetIE, KetnetIE,
Radio1BeIE, Radio1BeIE,
VRTMaxRadioIE,
VrtNUIE, VrtNUIE,
) )
from .vtm import VTMIE from .vtm import VTMIE

View File

@ -21,6 +21,7 @@ from ..utils import (
str_or_none, str_or_none,
strip_or_none, strip_or_none,
traverse_obj, traverse_obj,
try_call,
url_or_none, url_or_none,
urlencode_postdata, urlencode_postdata,
) )
@ -486,3 +487,124 @@ class Radio1BeIE(VRTBaseIE):
'description': self._html_search_meta(['description', 'og:description', 'twitter:description'], webpage), 'description': self._html_search_meta(['description', 'og:description', 'twitter:description'], webpage),
'thumbnail': self._html_search_meta(['og:image', 'twitter:image'], webpage), 'thumbnail': self._html_search_meta(['og:image', 'twitter:image'], webpage),
})) }))
class VRTMaxRadioIE(VRTBaseIE):
IE_DESC = 'VRT MAX (radio)'
_VALID_URL = r'https?://(?:www\.)?vrt\.be/(?:vrtmax|vrtnu)/luister/radio/(?P<show1l>[^/])/(?P<show>[^/]+)/(?P<episode_id>[^/?#&]+)/?'
_TESTS = [{
'url': 'https://www.vrt.be/vrtmax/luister/radio/d/duyster~11-177/duyster~11-27934-0/',
'md5': '14d002b1ebd8591ae360ff54a9b51515', # ... of first Fragment.
'info_dict': {
'id': 'duyster~11-27934-0',
'ext': 'mp4',
'title': 'DUYSTER.',
'description': 'DUYSTER. - maandag 10 juni 2024 om 22:00 | VRT MAX',
'thumbnail': 'https://images.vrt.be/vrtmax_prog_radio1/2023/10/05/1266f9e6-633c-11ee-91d7-02b7b76bf47f.png',
'timestamp': 1718049600,
'upload_date': '20240610',
'duration': 7200,
'channel': 'Radio 1',
'channel_url': 'https://www.vrt.be/vrtmax/kanalen/radio-1/',
'display_id': 'duyster~11-27934-0',
},
}, {
'url': 'https://www.vrt.be/vrtnu/luister/radio/n/nachtbaders~31-182/nachtbaders~31-22512-0/',
'md5': '85e9b0edf133f6638aa8d56581ac8773',
'info_dict': {
'id': 'nachtbaders~31-22512-0',
'ext': 'mp4',
'title': 'Nachtbaders',
'description': 'Nachtbaders - vrijdag 5 januari 2024 om 22:00 | VRT MAX | Nachtbaders Tom Soetaert en Niels Van Paemel dompelen je onder in de dromerige wereld van de neoklassiek. In hun queeste naar het beste uit het genre leggen ze de luisteraar te week in een bad van bedwelmende muziek van onder meer Max Richter, Bon Iver, Sigur Rós, Nils Frahm en Jóhann Jóhannson.',
'thumbnail': 'https://images.vrt.be/orig/2021/10/20/fdd5992e-31ad-11ec-b07d-02b7b76bf47f.jpg',
'timestamp': 1704488400.0,
'upload_date': '20240105',
'duration': 7200.0,
'channel': 'Klara',
'channel_url': 'https://www.vrt.be/vrtmax/kanalen/klara/',
'display_id': 'nachtbaders~31-22512-0',
},
}]
_GRAPHQUERY = '''query RadioEpisodePage($pageId: ID!) {
page(id: $pageId) {
... on RadioEpisodePage {
title
socialSharing {
title
}
player {
listenAction {
... on RadioEpisodeListenAction {
streamId
startDate
endDate
}
}
}
radioEpisode {
richDescription {
text
}
brand
image {
templateUrl
}
actionItems {
action {
... on LinkAction {
link
linkType
}
}
}
}
}
}
}'''
def get_metadata(self, show1l, show, episode_id):
# Rather fragile, download responds with nothing but "400: Bad Request" if any
# GraphQL part or header is out of place. Best to keep them minimal.
graphqlvar = f'/vrtnu/luister/radio/{show1l}/{show}/{episode_id}/'
postdata = json.dumps({
'query': self._GRAPHQUERY,
'variables': {'pageId': graphqlvar},
}).encode()
return self._download_json(
'https://www.vrt.be/vrtnu-api/graphql/public/v1', episode_id,
note='Downloading GraphQL metadata', data=postdata,
headers={
'content-type': 'application/json',
'Accept': 'application/graphql+json, application/json',
'Accept-Encoding': 'gzip, deflate, br',
'x-vrt-client-name': 'WEB',
})
def _real_extract(self, url):
(show1l, show, episode_id) = self._match_valid_url(url).groups()
metadata = self.get_metadata(show1l, show, episode_id)['data']['page']
audio_id = traverse_obj(metadata, ('player', 'listenAction', 'streamId'))
media_items = self._call_api(audio_id, 'vrtnu-web@PROD', version='v2')
formats, _ = self._extract_formats_and_subtitles(media_items, audio_id)
return {
'id': episode_id,
'formats': formats,
**traverse_obj(metadata, {
'title': 'title',
'description': ([('socialSharing', 'title'),
('radioEpisode', 'richDescription', 'text')],
all, {lambda txts: ' | '.join(txts) or None}),
'thumbnail': ('radioEpisode', 'image', 'templateUrl'),
'timestamp': ('player', 'listenAction', 'startDate', {lambda x: x / 1000}),
# Duration of original transmission, downloaded file is sometimes shorter:
'duration': ('player', 'listenAction',
{lambda a: try_call(lambda: (a['endDate'] - a['startDate']) / 1000)}),
'channel': ('radioEpisode', 'brand'),
'channel_url': ('radioEpisode', 'actionItems', ..., 'action', all,
lambda _, act: act.get('linkType') == 'channel', any,
'link', {lambda link: 'https://www.vrt.be' + link}),
}),
}