Skip to content

Commit 9791623

Browse files
committed
stream: refactor to_url and string representation
- Change format of Stream string representations and error messages of `to_url` and `to_manifest_url` - Don't override `__repr__` in `Stream` subclasses - Raise TypeError if url or manifest URL is None - Fix CLI - Abort passthrough if stream can't be translated to URL - Remove unneeded streamlink_cli.utils.stream module - Rewrite stream URL tests - Move FilmOnHLS stream URL tests to plugin test module (and rewrite)
1 parent df35fa5 commit 9791623

File tree

13 files changed

+182
-96
lines changed

13 files changed

+182
-96
lines changed

src/streamlink/plugins/filmon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def to_url(self):
123123
url = self.url
124124
expires = self.watch_timeout - time.time()
125125
if expires < 0:
126-
raise TypeError("Stream has expired and cannot be converted to a URL")
126+
raise TypeError("Stream has expired and cannot be translated to a URL")
127127
return url
128128

129129

src/streamlink/plugins/twitcasting.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ def __init__(self, session, url):
147147
super().__init__(session)
148148
self.url = url
149149

150-
def __repr__(self):
151-
return f"<TwitCastingStream({self.url!r})>"
150+
def to_url(self):
151+
return self.url
152152

153153
def open(self):
154154
reader = TwitCastingReader(self)

src/streamlink/stream/dash.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ def __json__(self):
184184

185185
return json
186186

187+
def to_url(self):
188+
if self.mpd.url is None:
189+
return super().to_url()
190+
191+
# the MPD URL has already been prepared by the initial request in `parse_manifest`
192+
return self.mpd.url
193+
187194
@classmethod
188195
def parse_manifest(
189196
cls,
@@ -305,9 +312,3 @@ def open(self):
305312
return video
306313
elif self.audio_representation:
307314
return audio
308-
309-
def to_url(self):
310-
return self.mpd.url
311-
312-
def to_manifest_url(self):
313-
return self.mpd.url

src/streamlink/stream/file.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,11 @@ def __init__(self, session, path=None, fileobj=None):
1414
if not self.path and not self.fileobj:
1515
raise ValueError("path or fileobj must be set")
1616

17+
def to_url(self):
18+
if self.path is None:
19+
return super().to_url()
20+
21+
return self.path
22+
1723
def open(self):
1824
return self.fileobj or open(self.path)

src/streamlink/stream/hls.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ def __init__(
490490
self.url_master = url_master
491491

492492
def to_manifest_url(self):
493+
if self.url_master is None:
494+
return super().to_manifest_url()
495+
493496
return self.url_master
494497

495498

@@ -527,9 +530,6 @@ def __init__(
527530
self.start_offset = start_offset
528531
self.duration = duration
529532

530-
def __repr__(self):
531-
return f"<HLSStream({self.url!r}, {self.url_master!r})>"
532-
533533
def __json__(self):
534534
json = super().__json__()
535535

@@ -543,6 +543,9 @@ def __json__(self):
543543
return json
544544

545545
def to_manifest_url(self):
546+
if self.url_master is None:
547+
return super().to_manifest_url()
548+
546549
args = self.args.copy()
547550
args.update(url=self.url_master)
548551

src/streamlink/stream/http.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ def __init__(
3333
self.args = dict(url=url, **args)
3434
self.buffered = buffered
3535

36-
def __repr__(self):
37-
return "<HTTPStream({0!r})>".format(self.url)
38-
3936
def __json__(self):
4037
req = self.session.http.prepare_new_request(**self.args)
4138

@@ -47,6 +44,9 @@ def __json__(self):
4744
body=req.body,
4845
)
4946

47+
def to_url(self):
48+
return self.url
49+
5050
@property
5151
def url(self) -> str:
5252
"""
@@ -71,6 +71,3 @@ def open(self):
7171
fd = StreamIOThreadWrapper(self.session, fd, timeout=timeout)
7272

7373
return fd
74-
75-
def to_url(self):
76-
return self.url

src/streamlink/stream/stream.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class Stream:
1313

1414
__shortname__ = "stream"
1515

16+
@classmethod
17+
def shortname(cls):
18+
return cls.__shortname__
19+
1620
def __init__(self, session):
1721
"""
1822
:param streamlink.Streamlink session: Streamlink session instance
@@ -21,11 +25,29 @@ def __init__(self, session):
2125
self.session = session
2226

2327
def __repr__(self):
24-
return "<Stream()>"
28+
params = [repr(self.shortname())]
29+
for method in self.to_url, self.to_manifest_url:
30+
try:
31+
params.append(repr(method()))
32+
except TypeError:
33+
pass
34+
35+
return f"<{self.__class__.__name__} [{', '.join(params)}]>"
2536

2637
def __json__(self):
2738
return dict(type=self.shortname())
2839

40+
@property
41+
def json(self):
42+
obj = self.__json__()
43+
return json.dumps(obj)
44+
45+
def to_url(self):
46+
raise TypeError(f"<{self.__class__.__name__} [{self.shortname()}]> cannot be translated to a URL")
47+
48+
def to_manifest_url(self):
49+
raise TypeError(f"<{self.__class__.__name__} [{self.shortname()}]> cannot be translated to a manifest URL")
50+
2951
def open(self) -> "StreamIO":
3052
"""
3153
Attempts to open a connection to the stream.
@@ -36,21 +58,6 @@ def open(self) -> "StreamIO":
3658

3759
raise NotImplementedError
3860

39-
@property
40-
def json(self):
41-
obj = self.__json__()
42-
return json.dumps(obj)
43-
44-
@classmethod
45-
def shortname(cls):
46-
return cls.__shortname__
47-
48-
def to_url(self):
49-
raise TypeError("{0} cannot be converted to a URL".format(self.shortname()))
50-
51-
def to_manifest_url(self):
52-
raise TypeError("{0} cannot be converted to a URL".format(self.shortname()))
53-
5461

5562
class StreamIO(io.IOBase):
5663
pass

src/streamlink_cli/main.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from streamlink_cli.console import ConsoleOutput, ConsoleUserInputRequester
3131
from streamlink_cli.constants import CONFIG_FILES, DEFAULT_STREAM_METADATA, LOG_DIR, PLUGIN_DIRS, STREAM_SYNONYMS
3232
from streamlink_cli.output import FileOutput, Output, PlayerOutput
33-
from streamlink_cli.utils import Formatter, HTTPServer, datetime, ignored, progress, stream_to_url
33+
from streamlink_cli.utils import Formatter, HTTPServer, datetime, ignored, progress
3434

3535
ACCEPTABLE_ERRNO = (errno.EPIPE, errno.EINVAL, errno.ECONNRESET)
3636
try:
@@ -257,11 +257,16 @@ def output_stream_passthrough(stream, formatter: Formatter):
257257
"""Prepares a filename to be passed to the player."""
258258
global output
259259

260-
filename = f'"{stream_to_url(stream)}"'
260+
try:
261+
url = stream.to_url()
262+
except TypeError:
263+
console.exit("The stream specified cannot be translated to a URL")
264+
return False
265+
261266
output = PlayerOutput(
262267
args.player,
263268
args=args.player_args,
264-
filename=filename,
269+
filename=f'"{url}"',
265270
call=True,
266271
quiet=not args.verbose_player,
267272
title=formatter.title(args.title, defaults=DEFAULT_STREAM_METADATA) if args.title else args.url

src/streamlink_cli/utils/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
from streamlink_cli.utils.http_server import HTTPServer
77
from streamlink_cli.utils.player import find_default_player
88
from streamlink_cli.utils.progress import progress
9-
from streamlink_cli.utils.stream import stream_to_url
109

1110
__all__ = [
1211
"Formatter", "HTTPServer", "JSONEncoder",
1312
"datetime",
14-
"find_default_player", "ignored", "progress", "stream_to_url"
13+
"find_default_player", "ignored", "progress",
1514
]
1615

1716

src/streamlink_cli/utils/stream.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)