feature: add private url scheme
* Also reformat code * Rename symbol LinkType.Song -> LinkType.Track
This commit is contained in:
parent
c00e881577
commit
3cb6653449
@ -1,4 +1,4 @@
|
||||
from .__version__ import __title__, __description__, __version__
|
||||
from .__main__ import main
|
||||
from .__version__ import __description__, __title__, __version__
|
||||
|
||||
__all__ = ["__title__", "__description__", "__version__", "main"]
|
||||
|
@ -93,7 +93,7 @@ def main(outputs: list[Path], exist: bool, overwrite: bool, quiet: bool, links:
|
||||
continue
|
||||
|
||||
match parsed.type:
|
||||
case LinkType.Song:
|
||||
case LinkType.Track:
|
||||
newTrack = api.getDetailsForTrack(parsed.id)
|
||||
savePath = pickOutput(newTrack, outputs, exist)
|
||||
|
||||
|
@ -29,6 +29,6 @@ class LrcMetaType(Enum):
|
||||
|
||||
|
||||
class LinkType(Enum):
|
||||
Song = auto()
|
||||
Album = auto()
|
||||
Playlist = auto()
|
||||
Track = "track"
|
||||
Album = "album"
|
||||
Playlist = "playlist"
|
||||
|
@ -12,7 +12,8 @@ from .object import NCMTrack
|
||||
|
||||
__all__ = ["Link", "parseLink", "testExistTrackSource", "pickOutput"]
|
||||
|
||||
RE_ANDROID_ALBUM_SHARE_LINK_PATH = reCompile(r"^/album/(?P<id>\d*)/?$")
|
||||
RE_SHARE_LINK_ID_BY_PATH = reCompile(r"^/?(?P<id>\d+)$")
|
||||
RE_SHARE_LINK_ANDROID_ALBUM_PATH = reCompile(r"^/album/(?P<id>\d+)/?$")
|
||||
RE_SAFE_FILENAME = reCompile(r"\*{2,}")
|
||||
TRANSLATER_SAFE_FILENAME = str.maketrans({i: 0x2A for i in ("<", ">", ":", '"', "/", "\\", "|", "?")})
|
||||
|
||||
@ -28,39 +29,72 @@ def parseLink(url: str) -> Link:
|
||||
contentType: LinkType | None = None
|
||||
contentId: int | None = None
|
||||
|
||||
match parsedUrl.netloc:
|
||||
case "music.163.com":
|
||||
match parsedUrl.path:
|
||||
case "/playlist" | "/#/playlist":
|
||||
contentType = LinkType.Playlist
|
||||
case "/album" | "/#/album":
|
||||
contentType = LinkType.Album
|
||||
case "/song" | "/#/song":
|
||||
contentType = LinkType.Song
|
||||
case _:
|
||||
# Hack for android client shared album link
|
||||
matchedPath = RE_ANDROID_ALBUM_SHARE_LINK_PATH.match(parsedUrl.path)
|
||||
if matchedPath is not None:
|
||||
contentType = LinkType.Album
|
||||
contentId = int(matchedPath["id"])
|
||||
else:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
case "y.music.163.com":
|
||||
match parsedUrl.path:
|
||||
case "/m/playlist":
|
||||
contentType = LinkType.Playlist
|
||||
case "/m/song":
|
||||
contentType = LinkType.Song
|
||||
match parsedUrl.scheme:
|
||||
case "http" | "https":
|
||||
match parsedUrl.netloc:
|
||||
case "music.163.com":
|
||||
match parsedUrl.path:
|
||||
case "/playlist" | "/#/playlist":
|
||||
contentType = LinkType.Playlist
|
||||
case "/album" | "/#/album":
|
||||
contentType = LinkType.Album
|
||||
case "/song" | "/#/song":
|
||||
contentType = LinkType.Track
|
||||
case _:
|
||||
# Hack for android client shared album link
|
||||
matchedPath = RE_SHARE_LINK_ANDROID_ALBUM_PATH.match(parsedUrl.path)
|
||||
if matchedPath is not None:
|
||||
contentType = LinkType.Album
|
||||
contentId = int(matchedPath["id"])
|
||||
else:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
case "y.music.163.com":
|
||||
match parsedUrl.path:
|
||||
case "/m/playlist":
|
||||
contentType = LinkType.Playlist
|
||||
case "/m/song":
|
||||
contentType = LinkType.Track
|
||||
case _:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
case "163cn.tv":
|
||||
response = httpGet(url)
|
||||
if response.status_code != 302:
|
||||
raise ParseLinkError(f"未知的 Api 响应: {response.status_code}")
|
||||
newUrl = response.headers.get("Location")
|
||||
if newUrl is None:
|
||||
raise ParseLinkError("Api 未返回重定向结果")
|
||||
return parseLink(newUrl)
|
||||
case _:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
case "163cn.tv":
|
||||
response = httpGet(url)
|
||||
if response.status_code != 302:
|
||||
raise ParseLinkError(f"未知的 Api 响应: {response.status_code}")
|
||||
newUrl = response.headers.get("Location")
|
||||
if newUrl is None:
|
||||
raise ParseLinkError("Api 未返回重定向结果")
|
||||
return parseLink(newUrl)
|
||||
case "ncmlyrics": # eg: ncmlyrics://playlist/123456, ncmlyrics://album/12456, ncmlyrics://track/123456
|
||||
try:
|
||||
contentType = LinkType(parsedUrl.netloc)
|
||||
except ValueError:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
|
||||
if parsedUrl.path:
|
||||
matched = RE_SHARE_LINK_ID_BY_PATH.match(parsedUrl.path)
|
||||
if matched is not None:
|
||||
contentId = int(matched.group("id"))
|
||||
else:
|
||||
raise ParseLinkError
|
||||
case "playlist" | "album" | "track": # eg: playlist:123456, album:/12456, track://123456
|
||||
try:
|
||||
contentType = LinkType(parsedUrl.scheme)
|
||||
except ValueError:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
|
||||
try:
|
||||
if parsedUrl.netloc:
|
||||
contentId = int(parsedUrl.netloc)
|
||||
elif parsedUrl.path:
|
||||
matched = RE_SHARE_LINK_ID_BY_PATH.match(parsedUrl.path)
|
||||
if matched is not None:
|
||||
contentId = int(matched.group("id"))
|
||||
else:
|
||||
raise ParseLinkError
|
||||
except ValueError:
|
||||
raise ParseLinkError
|
||||
case _:
|
||||
raise UnsupportedLinkError(parsedUrl)
|
||||
|
||||
|
@ -23,7 +23,7 @@ class TestUtils(TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("https://music.163.com/song?id=2621105420"),
|
||||
Link(LinkType.Song, 2621105420),
|
||||
Link(LinkType.Track, 2621105420),
|
||||
msg="Shared song from NCM Windows Client",
|
||||
)
|
||||
|
||||
@ -42,7 +42,7 @@ class TestUtils(TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("https://music.163.com/#/song?id=2621105420"),
|
||||
Link(LinkType.Song, 2621105420),
|
||||
Link(LinkType.Track, 2621105420),
|
||||
msg="Song from NCM Website",
|
||||
)
|
||||
|
||||
@ -61,18 +61,55 @@ class TestUtils(TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("https://y.music.163.com/m/song?id=2604307454"),
|
||||
Link(LinkType.Song, 2604307454),
|
||||
Link(LinkType.Track, 2604307454),
|
||||
msg="Shared song from NCM Android Client",
|
||||
)
|
||||
|
||||
def test_parseLink_302(self):
|
||||
self.assertEqual(
|
||||
parseLink("http://163cn.tv/xpaQwii"),
|
||||
Link(LinkType.Song, 413077069),
|
||||
Link(LinkType.Track, 413077069),
|
||||
msg="Shared song from NCM Android Client player",
|
||||
)
|
||||
|
||||
def test_parseLink_UnsupportShareLinkError(self):
|
||||
def test_parseLink_special(self):
|
||||
self.assertEqual(
|
||||
parseLink("ncmlyrics://playlist/123456"),
|
||||
Link(LinkType.Playlist, 123456),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("ncmlyrics://album/123456"),
|
||||
Link(LinkType.Album, 123456),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("ncmlyrics://track/123456"),
|
||||
Link(LinkType.Track, 123456),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("playlist:123456"),
|
||||
Link(LinkType.Playlist, 123456),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("album:/123456"),
|
||||
Link(LinkType.Album, 123456),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
parseLink("track://123456"),
|
||||
Link(LinkType.Track, 123456),
|
||||
)
|
||||
|
||||
def test_parseLink_UnsupportedLinkError(self):
|
||||
self.assertRaises(
|
||||
UnsupportedLinkError,
|
||||
parseLink,
|
||||
"ftp://ftpserver.com/",
|
||||
)
|
||||
|
||||
self.assertRaises(
|
||||
UnsupportedLinkError,
|
||||
parseLink,
|
||||
@ -91,13 +128,25 @@ class TestUtils(TestCase):
|
||||
"https://music.163.com/album/123a",
|
||||
)
|
||||
|
||||
def test_parseLink_ParseShareLinkError(self):
|
||||
self.assertRaises(
|
||||
UnsupportedLinkError,
|
||||
parseLink,
|
||||
"ncmlyrics://unsupport/123456",
|
||||
)
|
||||
|
||||
def test_parseLink_ParseLinkError(self):
|
||||
self.assertRaises(
|
||||
ParseLinkError,
|
||||
parseLink,
|
||||
"https://music.163.com/playlist?id=123a",
|
||||
)
|
||||
|
||||
self.assertRaises(
|
||||
ParseLinkError,
|
||||
parseLink,
|
||||
"playlist://123456a",
|
||||
)
|
||||
|
||||
def test_testExistTrackSource(self):
|
||||
resources = Path("tests/resource/util/testExistTrackSource")
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user