mirror of
https://github.com/oskvr37/tiddl.git
synced 2026-06-13 12:15:13 +03:00
✨ add formatTrack
This commit is contained in:
+98
-1
@@ -1,6 +1,8 @@
|
||||
import unittest
|
||||
import json
|
||||
|
||||
from tiddl.utils import TidalResource
|
||||
from tiddl.models import Track
|
||||
from tiddl.utils import TidalResource, formatTrack
|
||||
|
||||
|
||||
class TestTidalResource(unittest.TestCase):
|
||||
@@ -42,5 +44,100 @@ class TestTidalResource(unittest.TestCase):
|
||||
TidalResource(resource)
|
||||
|
||||
|
||||
class TestFormatTrack(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.track = Track(
|
||||
**{
|
||||
"id": 66421438,
|
||||
"title": "Shutdown",
|
||||
"duration": 189,
|
||||
"replayGain": -9.95,
|
||||
"peak": 0.966051,
|
||||
"allowStreaming": True,
|
||||
"streamReady": True,
|
||||
"adSupportedStreamReady": True,
|
||||
"djReady": True,
|
||||
"stemReady": False,
|
||||
"streamStartDate": "2016-11-15T00:00:00.000+0000",
|
||||
"premiumStreamingOnly": False,
|
||||
"trackNumber": 9,
|
||||
"volumeNumber": 1,
|
||||
"version": None,
|
||||
"popularity": 24,
|
||||
"copyright": "(P) 2016 Boy Better Know",
|
||||
"bpm": 69,
|
||||
"url": "http://www.tidal.com/track/66421438",
|
||||
"isrc": "GB7QY1500024",
|
||||
"editable": False,
|
||||
"explicit": True,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"audioModes": ["STEREO"],
|
||||
"mediaMetadata": {"tags": ["LOSSLESS", "HIRES_LOSSLESS"]},
|
||||
"artist": {
|
||||
"id": 3566984,
|
||||
"name": "Skepta",
|
||||
"type": "MAIN",
|
||||
"picture": "747af850-fa9c-4178-a3e6-49259b67df86",
|
||||
},
|
||||
"artists": [
|
||||
{
|
||||
"id": 3566984,
|
||||
"name": "Skepta",
|
||||
"type": "MAIN",
|
||||
"picture": "747af850-fa9c-4178-a3e6-49259b67df86",
|
||||
}
|
||||
],
|
||||
"album": {
|
||||
"id": 66421429,
|
||||
"title": "Konnichiwa",
|
||||
"cover": "e0c2f05e-e21f-47c5-9c37-2993437df27d",
|
||||
"vibrantColor": "#ae3b31",
|
||||
"videoCover": None,
|
||||
},
|
||||
"mixes": {"TRACK_MIX": "001aa4abeb471e8f55f5784772b478"},
|
||||
"playlistNumber": None,
|
||||
}
|
||||
)
|
||||
|
||||
def test_templating(self):
|
||||
test_cases = [
|
||||
("{id}", "66421438"),
|
||||
("{title}", "Shutdown"),
|
||||
("{version}", ""),
|
||||
("{artist}", "Skepta"),
|
||||
("{artists}", "Skepta"),
|
||||
("{album}", "Konnichiwa"),
|
||||
("{number}", "9"),
|
||||
("{disc}", "1"),
|
||||
("{date}", "11-15-16"),
|
||||
("{year}", "2016"),
|
||||
("{playlist_number}", ""),
|
||||
("{bpm}", "69"),
|
||||
("{quality}", "high"),
|
||||
("{artist}/{album}/{title}", "Skepta/Konnichiwa/Shutdown"),
|
||||
]
|
||||
|
||||
for template, expected_result in test_cases:
|
||||
result = formatTrack(template, self.track)
|
||||
self.assertEqual(result, expected_result)
|
||||
|
||||
def test_invalid_characters(self):
|
||||
test_cases = [
|
||||
"\\",
|
||||
":",
|
||||
'"',
|
||||
"?",
|
||||
"<",
|
||||
">",
|
||||
"|",
|
||||
]
|
||||
|
||||
for template in test_cases:
|
||||
with self.subTest(template=template):
|
||||
with self.assertRaises(ValueError):
|
||||
formatTrack(template, self.track)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import re
|
||||
from urllib.parse import urlparse
|
||||
from typing import Literal, get_args
|
||||
|
||||
from tiddl.models import Track, QUALITY_TO_ARG
|
||||
|
||||
ResourceTypeLiteral = Literal["track", "album", "playlist", "artist"]
|
||||
|
||||
@@ -39,3 +41,51 @@ class TidalResource:
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.resource_type}/{self.resource_id}"
|
||||
|
||||
|
||||
def sanitizeString(string: str) -> str:
|
||||
pattern = r'[\\/:"*?<>|]+'
|
||||
return re.sub(pattern, "", string)
|
||||
|
||||
|
||||
def formatTrack(template: str, track: Track, date_format="%x") -> str:
|
||||
disallowed_chars = r'[\\:"*?<>|]+'
|
||||
invalid_chars = re.findall(disallowed_chars, template)
|
||||
|
||||
if invalid_chars:
|
||||
raise ValueError(
|
||||
f"Template '{template}' contains disallowed characters: {' '.join(sorted(set(invalid_chars)))}"
|
||||
)
|
||||
|
||||
artist = track.artist.name if track.artist else ""
|
||||
features = [
|
||||
track_artist.name
|
||||
for track_artist in track.artists
|
||||
if track_artist.name != artist
|
||||
]
|
||||
|
||||
track_dict: dict[str, str] = {
|
||||
"id": str(track.id),
|
||||
"title": track.title,
|
||||
"version": track.version or "",
|
||||
"artist": artist,
|
||||
"artists": ", ".join(features + [artist]),
|
||||
"features": ", ".join(features),
|
||||
"album": track.album.title,
|
||||
"number": str(track.trackNumber),
|
||||
"disc": str(track.volumeNumber),
|
||||
"date": (
|
||||
track.streamStartDate.strftime(date_format).replace("/", "-")
|
||||
if track.streamStartDate
|
||||
else ""
|
||||
),
|
||||
"year": track.streamStartDate.strftime("%Y") if track.streamStartDate else "",
|
||||
"playlist_number": str(track.playlistNumber or ""),
|
||||
"bpm": str(track.bpm or ""),
|
||||
"quality": QUALITY_TO_ARG[track.audioQuality],
|
||||
}
|
||||
|
||||
for key, value in track_dict.items():
|
||||
track_dict[key] = sanitizeString(value)
|
||||
|
||||
return template.format(**track_dict)
|
||||
|
||||
Reference in New Issue
Block a user