Streaming (host-owned file I/O)#
client.stream(url) resolves a track link and returns a
MediaStream of plaintext audio bytes — decrypted
if Tidal served an encrypted rendition, remuxed containers resolved
to their audio payload. No disk I/O happens anywhere in the
library. This is the integration path for hosts that store media
in S3, PostgreSQL, or anywhere else the library knows nothing about.
Basic use#
with client.stream("https://tidal.com/track/12345678") as media:
for chunk in media.chunks(): # 256 KiB chunks by default
sink.write(chunk)
MediaStream is a thin, thread-reading wrapper around the resolved
StreamInfo:
media.chunks(chunk_size)— lazy iterator ofbytes(the chunk size is a hint, not a promise);media.read(n=-1)/media.readinto(buf)— buffered reads, with a proper leftover buffer (a partial read never loses bytes);media.size— total plaintext size when it can be determined (cached), else-1;media.delivered_quality,media.codec— what you’re getting;media.track_id— the Tidal track id (for naming the stored object);context manager /
media.close()— releases the client’s operation registration;iterating raises
CancelledErrorwhen the client’s cancellation fires (by design: the host decides what to do with the partial data it already has).
S3 multipart example#
import boto3
from tidalpy import Config, TidalClient
s3 = boto3.client("s3")
client = TidalClient(Config(token_path="~/.tidalpy/token.json"))
with client.stream(track_url) as media:
key = f"tidal/{media.track_id}.flac"
upload = s3.create_multipart_upload(Bucket=BUCKET, Key=key)
part_number = 0
parts = []
for chunk in media.chunks():
part_number += 1
resp = s3.upload_part(
Bucket=BUCKET, Key=key,
PartNumber=part_number, Body=chunk,
)
parts.append({"ETag": resp["ETag"],
"PartNumber": part_number})
s3.complete_multipart_upload(
Bucket=BUCKET, Key=key,
MultipartUpload={"UploadId": upload["UploadId"], "Parts": parts},
)
Caveats#
One track per stream. For collections, iterate
client.list_items(url)and stream each track link.The stream is pulled by the host: a slow sink simply slows the network (there is no unbounded buffering).
Streams do not write tags — the host owns the final object.