-
-
Notifications
You must be signed in to change notification settings - Fork 346
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Describe the bug
when a tidal url has the /u suffix it messes the detection. I get this url by right clicking a song on tidal and then clicking copy, so standard procedure. I think it so common we should support it
I plan to make a PR
$ rip url 'https://tidal.com/track/53796003/u'
...
TypeError: not all arguments converted during string formattingCommand Used
rip url 'https://tidal.com/track/53796003/u'Debug Traceback
$ rip -vvv url 'https://tidal.com/track/53796003/u'
[20:50:59] DEBUG Showing all debug logs cli.py:111
DEBUG Executing SELECT EXISTS(SELECT 1 FROM downloads WHERE id=?) db.py:108
DEBUG Removing dirs set() artwork.py:19
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/ivan/.local/bin/rip:10 in <module> │
│ │
│ 7 │ │ sys.argv[0] = sys.argv[0][:-11] │
│ 8 │ elif sys.argv[0].endswith(".exe"): │
│ 9 │ │ sys.argv[0] = sys.argv[0][:-4] │
│ ❱ 10 │ sys.exit(rip()) │
│ 11 │
│ │
│ ╭──────────── locals ─────────────╮ │
│ │ rip = <HelpColorsGroup rip> │ │
│ │ sys = <module 'sys' (built-in)> │ │
│ ╰─────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/core.py:1462 in │
│ __call__ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/core.py:1383 in │
│ main │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/core.py:1850 in │
│ invoke │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/core.py:1246 in │
│ invoke │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/core.py:814 in │
│ invoke │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/click/decorators.py:34 │
│ in new_func │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/rip/cli.py:29 │
│ in wrapper │
│ │
│ 26 def coro(f): │
│ 27 │ @wraps(f) │
│ 28 │ def wrapper(*args, **kwargs): │
│ ❱ 29 │ │ return asyncio.run(f(*args, **kwargs)) │
│ 30 │ │
│ 31 │ return wrapper │
│ 32 │
│ │
│ ╭────────────────────────── locals ──────────────────────────╮ │
│ │ args = (<click.core.Context object at 0x7f035615efd0>,) │ │
│ │ kwargs = {'urls': ('https://tidal.com/track/53796003/u',)} │ │
│ ╰────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/asyncio/runners.py:195 in run │
│ │
│ 192 │ │ │ "asyncio.run() cannot be called from a running event loop") │
│ 193 │ │
│ 194 │ with Runner(debug=debug, loop_factory=loop_factory) as runner: │
│ ❱ 195 │ │ return runner.run(main) │
│ 196 │
│ 197 │
│ 198 def _cancel_all_tasks(loop): │
│ │
│ ╭───────────────────────────── locals ─────────────────────────────╮ │
│ │ debug = None │ │
│ │ loop_factory = None │ │
│ │ main = <coroutine object url at 0x7f03566aed60> │ │
│ │ runner = <asyncio.runners.Runner object at 0x7f0356667b60> │ │
│ ╰──────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/asyncio/runners.py:118 in run │
│ │
│ 115 │ │ │
│ 116 │ │ self._interrupt_count = 0 │
│ 117 │ │ try: │
│ ❱ 118 │ │ │ return self._loop.run_until_complete(task) │
│ 119 │ │ except exceptions.CancelledError: │
│ 120 │ │ │ if self._interrupt_count > 0: │
│ 121 │ │ │ │ uncancel = getattr(task, "uncancel", None) │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ context = <_contextvars.Context object at 0x7f03566f2a80> │ │
│ │ coro = <coroutine object url at 0x7f03566aed60> │ │
│ │ self = <asyncio.runners.Runner object at 0x7f0356667b60> │ │
│ │ sigint_handler = functools.partial(<bound method Runner._on_sigint of │ │
│ │ <asyncio.runners.Runner object at 0x7f0356667b60>>, main_task=<Task │ │
│ │ finished name='Task-1' coro=<url() done, defined at │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/st… │ │
│ │ exception=TypeError('not all arguments converted during string │ │
│ │ formatting')>) │ │
│ │ task = <Task finished name='Task-1' coro=<url() done, defined at │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/st… │ │
│ │ exception=TypeError('not all arguments converted during string │ │
│ │ formatting')> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/asyncio/base_events.py:725 in run_until_complete │
│ │
│ 722 │ │ if not future.done(): │
│ 723 │ │ │ raise RuntimeError('Event loop stopped before Future completed.') │
│ 724 │ │ │
│ ❱ 725 │ │ return future.result() │
│ 726 │ │
│ 727 │ def stop(self): │
│ 728 │ │ """Stop running the event loop. │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ future = <Task finished name='Task-1' coro=<url() done, defined at │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamri… │ │
│ │ exception=TypeError('not all arguments converted during string formatting')> │ │
│ │ new_task = False │ │
│ │ self = <_UnixSelectorEventLoop running=False closed=True debug=False> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/rip/cli.py:192 │
│ in url │
│ │
│ 189 │ │ │ │
│ 190 │ │ │ async with Main(cfg) as main: │
│ 191 │ │ │ │ await main.add_all(urls) │
│ ❱ 192 │ │ │ │ await main.resolve() │
│ 193 │ │ │ │ await main.rip() │
│ 194 │ │ │ │
│ 195 │ │ │ if version_coro is not None: │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ cfg = <streamrip.config.Config object at 0x7f0356667770> │ │
│ │ ctx = <click.core.Context object at 0x7f035615efd0> │ │
│ │ main = <streamrip.rip.main.Main object at 0x7f0356170d70> │ │
│ │ updates = True │ │
│ │ urls = ('https://tidal.com/track/53796003/u',) │ │
│ │ version_coro = <Task finished name='Task-2' coro=<latest_streamrip_version() done, defined │ │
│ │ at │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/stre… │ │
│ │ result=('2.1.0', None)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/rip/main.py:16 │
│ 0 in resolve │
│ │
│ 157 │ │ with console.status("Resolving URLs...", spinner="dots"): │
│ 158 │ │ │ coros = [p.resolve() for p in self.pending] │
│ 159 │ │ │ new_media: list[Media] = [ │
│ ❱ 160 │ │ │ │ m for m in await asyncio.gather(*coros) if m is not None │
│ 161 │ │ │ ] │
│ 162 │ │ │
│ 163 │ │ self.media.extend(new_media) │
│ │
│ ╭─────────────────────────────── locals ───────────────────────────────╮ │
│ │ coros = [<coroutine object PendingSingle.resolve at 0x7f03566678b0>] │ │
│ │ self = <streamrip.rip.main.Main object at 0x7f0356170d70> │ │
│ ╰──────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/media/track.py │
│ :195 in resolve │
│ │
│ 192 │ │ │ return None │
│ 193 │ │ │
│ 194 │ │ try: │
│ ❱ 195 │ │ │ resp = await self.client.get_metadata(self.id, "track") │
│ 196 │ │ except NonStreamableError as e: │
│ 197 │ │ │ logger.error(f"Error fetching track {self.id}: {e}") │
│ 198 │ │ │ return None │
│ │
│ ╭───────────────────────────────────── locals ─────────────────────────────────────╮ │
│ │ self = PendingSingle( │ │
│ │ │ id='u', │ │
│ │ │ client=<streamrip.client.tidal.TidalClient object at 0x7f0356171010>, │ │
│ │ │ config=<streamrip.config.Config object at 0x7f0356667770>, │ │
│ │ │ db=Database( │ │
│ │ │ │ downloads=<streamrip.db.Downloads object at 0x7f0356171e80>, │ │
│ │ │ │ failed=<streamrip.db.Failed object at 0x7f0356171fd0> │ │
│ │ │ ) │ │
│ │ ) │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/client/tidal.p │
│ y:90 in get_metadata │
│ │
│ 87 │ │ ), media_type │
│ 88 │ │ │
│ 89 │ │ url = f"{media_type}s/{item_id}" │
│ ❱ 90 │ │ item = await self._api_request(url) │
│ 91 │ │ if media_type in ("playlist", "album"): │
│ 92 │ │ │ # TODO: move into new method and make concurrent │
│ 93 │ │ │ resp = await self._api_request(f"{url}/items") │
│ │
│ ╭────────────────────────────────── locals ──────────────────────────────────╮ │
│ │ item_id = 'u' │ │
│ │ media_type = 'track' │ │
│ │ self = <streamrip.client.tidal.TidalClient object at 0x7f0356171010> │ │
│ │ url = 'tracks/u' │ │
│ ╰────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/client/tidal.p │
│ y:358 in _api_request │
│ │
│ 355 │ │ async with self.rate_limiter: │
│ 356 │ │ │ async with self.session.get(f"{base}/{path}", params=params) as resp: │
│ 357 │ │ │ │ if resp.status == 404: │
│ ❱ 358 │ │ │ │ │ logger.warning("TIDAL: track not found", resp) │
│ 359 │ │ │ │ │ raise NonStreamableError("TIDAL: Track not found") │
│ 360 │ │ │ │ resp.raise_for_status() │
│ 361 │ │ │ │ return await resp.json() │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ base = 'https://api.tidalhifi.com/v1' │ │
│ │ params = {'countryCode': 'MX', 'limit': 100} │ │
│ │ path = 'tracks/u' │ │
│ │ resp = <ClientResponse(https://api.tidalhifi.com/v1/tracks/u?countryCode=MX&limit=100) │ │
│ │ [404 Not Found]> │ │
│ │ <CIMultiDictProxy('Content-Type': 'application/json', 'Content-Length': '66', │ │
│ │ 'Connection': 'keep-alive', 'Date': 'Sun, 16 Nov 2025 02:50:59 GMT', 'Server': │ │
│ │ 'noyb', 'Cache-Control': 'no-cache', 'X-Cache': 'Error from cloudfront', 'Via': │ │
│ │ '1.1 REDACTED.cloudfront.net (CloudFront)', 'X-Amz-Cf-Pop': │ │
│ │ 'REDACTED', 'X-Amz-Cf-Id': │ │
│ │ '64-REDACTED==')> │ │
│ │ self = <streamrip.client.tidal.TidalClient object at 0x7f0356171010> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:1532 in warning │
│ │
│ 1529 │ │ logger.warning("Houston, we have a %s", "bit of a problem", exc_info=True) │
│ 1530 │ │ """ │
│ 1531 │ │ if self.isEnabledFor(WARNING): │
│ ❱ 1532 │ │ │ self._log(WARNING, msg, args, **kwargs) │
│ 1533 │ │
│ 1534 │ def warn(self, msg, *args, **kwargs): │
│ 1535 │ │ warnings.warn("The 'warn' method is deprecated, " │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ args = ( │ │
│ │ │ <ClientResponse(https://api.tidalhifi.com/v1/tracks/u?countryCode=MX&limit=100) │ │
│ │ [404 Not Found]> │ │
│ │ <CIMultiDictProxy('Content-Type': 'application/json', 'Content-Length': '66', │ │
│ │ 'Connection': 'keep-alive', 'Date': 'Sun, 16 Nov 2025 02:50:59 GMT', 'Server': │ │
│ │ 'noyb', 'Cache-Control': 'no-cache', 'X-Cache': 'Error from cloudfront', 'Via': │ │
│ │ '1.1 REDACTED.cloudfront.net (CloudFront)', 'X-Amz-Cf-Pop': │ │
│ │ 'REDACTED', 'X-Amz-Cf-Id': │ │
│ │ '64-REDACTED==')> │ │
│ │ , │ │
│ │ ) │ │
│ │ kwargs = {} │ │
│ │ msg = 'TIDAL: track not found' │ │
│ │ self = <Logger streamrip (DEBUG)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:1665 in _log │
│ │
│ 1662 │ │ │ │ exc_info = sys.exc_info() │
│ 1663 │ │ record = self.makeRecord(self.name, level, fn, lno, msg, args, │
│ 1664 │ │ │ │ │ │ │ │ exc_info, func, extra, sinfo) │
│ ❱ 1665 │ │ self.handle(record) │
│ 1666 │ │
│ 1667 │ def handle(self, record): │
│ 1668 │ │ """ │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ args = ( │ │
│ │ │ │ │
│ │ <ClientResponse(https://api.tidalhifi.com/v1/tracks/u?countryCode=MX&limit=100) │ │
│ │ [404 Not Found]> │ │
│ │ <CIMultiDictProxy('Content-Type': 'application/json', 'Content-Length': '66', │ │
│ │ 'Connection': 'keep-alive', 'Date': 'Sun, 16 Nov 2025 02:50:59 GMT', 'Server': │ │
│ │ 'noyb', 'Cache-Control': 'no-cache', 'X-Cache': 'Error from cloudfront', 'Via': │ │
│ │ '1.1 REDACTED.cloudfront.net (CloudFront)', │ │
│ │ 'X-Amz-Cf-Pop': 'REDACTED', 'X-Amz-Cf-Id': │ │
│ │ '64-REDACTED==')> │ │
│ │ , │ │
│ │ ) │ │
│ │ exc_info = None │ │
│ │ extra = None │ │
│ │ fn = '/home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/strea… │ │
│ │ func = '_api_request' │ │
│ │ level = 30 │ │
│ │ lno = 358 │ │
│ │ msg = 'TIDAL: track not found' │ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/stream… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <Logger streamrip (DEBUG)> │ │
│ │ sinfo = None │ │
│ │ stack_info = False │ │
│ │ stacklevel = 1 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:1681 in handle │
│ │
│ 1678 │ │ │ return │
│ 1679 │ │ if isinstance(maybe_record, LogRecord): │
│ 1680 │ │ │ record = maybe_record │
│ ❱ 1681 │ │ self.callHandlers(record) │
│ 1682 │ │
│ 1683 │ def addHandler(self, hdlr): │
│ 1684 │ │ """ │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ maybe_record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/stre… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/stre… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <Logger streamrip (DEBUG)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:1737 in callHandlers │
│ │
│ 1734 │ │ │ for hdlr in c.handlers: │
│ 1735 │ │ │ │ found = found + 1 │
│ 1736 │ │ │ │ if record.levelno >= hdlr.level: │
│ ❱ 1737 │ │ │ │ │ hdlr.handle(record) │
│ 1738 │ │ │ if not c.propagate: │
│ 1739 │ │ │ │ c = None #break out │
│ 1740 │ │ │ else: │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ c = <RootLogger root (INFO)> │ │
│ │ found = 1 │ │
│ │ hdlr = <RichHandler (NOTSET)> │ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <Logger streamrip (DEBUG)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:1027 in handle │
│ │
│ 1024 │ │ │ record = rv │
│ 1025 │ │ if rv: │
│ 1026 │ │ │ with self.lock: │
│ ❱ 1027 │ │ │ │ self.emit(record) │
│ 1028 │ │ return rv │
│ 1029 │ │
│ 1030 │ def setFormatter(self, fmt): │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ rv = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <RichHandler (NOTSET)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/rich/logging.py:134 in │
│ emit │
│ │
│ 131 │ │
│ 132 │ def emit(self, record: LogRecord) -> None: │
│ 133 │ │ """Invoked by logging.""" │
│ ❱ 134 │ │ message = self.format(record) │
│ 135 │ │ traceback = None │
│ 136 │ │ if ( │
│ 137 │ │ │ self.rich_tracebacks │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <RichHandler (NOTSET)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:999 in format │
│ │
│ 996 │ │ │ fmt = self.formatter │
│ 997 │ │ else: │
│ 998 │ │ │ fmt = _defaultFormatter │
│ ❱ 999 │ │ return fmt.format(record) │
│ 1000 │ │
│ 1001 │ def emit(self, record): │
│ 1002 │ │ """ │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ fmt = <logging.Formatter object at 0x7f035615e0d0> │ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <RichHandler (NOTSET)> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:712 in format │
│ │
│ 709 │ │ called to format the event time. If there is exception information, │
│ 710 │ │ it is formatted using formatException() and appended to the message. │
│ 711 │ │ """ │
│ ❱ 712 │ │ record.message = record.getMessage() │
│ 713 │ │ if self.usesTime(): │
│ 714 │ │ │ record.asctime = self.formatTime(record, self.datefmt) │
│ 715 │ │ s = self.formatMessage(record) │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ record = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ │ self = <logging.Formatter object at 0x7f035615e0d0> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ /usr/lib/python3.13/logging/__init__.py:400 in getMessage │
│ │
│ 397 │ │ """ │
│ 398 │ │ msg = str(self.msg) │
│ 399 │ │ if self.args: │
│ ❱ 400 │ │ │ msg = msg % self.args │
│ 401 │ │ return msg │
│ 402 │
│ 403 # │
│ │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ msg = 'TIDAL: track not found' │ │
│ │ self = <LogRecord: streamrip, 30, │ │
│ │ /home/ivan/.local/share/uv/tools/streamrip/lib/python3.13/site-packages/streamrip/cl… │ │
│ │ 358, "TIDAL: track not found"> │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: not all arguments converted during string formattingConfig File
not needed
Operating System
Linux
streamrip version
rip, version 2.1.0
Screenshots and recordings
No response
Additional context
No response
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working