From 225f83f5a5f077d7b7f7c476f825a0ded8008b74 Mon Sep 17 00:00:00 2001 From: Pawky Languish Date: Thu, 28 Nov 2024 18:49:54 +0000 Subject: add apple music --- applemusic.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bandcamp.py | 10 +----- soundcloud.py | 2 +- spotify.py | 2 +- test.sh | 4 +++ youtube.py | 13 ++++--- 6 files changed, 125 insertions(+), 16 deletions(-) create mode 100755 applemusic.py diff --git a/applemusic.py b/applemusic.py new file mode 100755 index 0000000..9e10ab9 --- /dev/null +++ b/applemusic.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +from html.parser import HTMLParser +from urllib.request import urlopen +from urllib.parse import urlencode, urlparse +from json import loads as json_loads + + +class AppleMusic: + video_type = "" + + def mesg(self, msg, t=None): + self.util.mesg(msg, t) + + def match_urls(self, str): + r = [i for i in str.split() if "https://music.apple.com" in i] + r = list(dict.fromkeys(r)) + n = 0 + for i in r: + if not i.startswith("http"): + r.pop(n) + n += 1 + + return r + + class parseprop(HTMLParser): + def __init__(self): + # print("applemusic parse init") + HTMLParser.__init__(self) + self.ldjson = False + + def handle_starttag(self, tag, attrs): + if tag == "script" and ("type", "application/ld+json") in attrs: + self.ldjson = True + else: + self.ldjson = False + + def handle_endtag(self, tag): + self.ldjson = False + + def handle_data(self, data): + if self.ldjson: + AppleMusic.ldjson = data + return + + def is_album(self, url): + return "/album/" in url + + def applemusic_oembed(self, url): + url = urlparse(url) + url = url.scheme + "://" + url.netloc + url.path + url = f"https://music.apple.com/api/oembed?{urlencode([('url',url),('format','json')])}" + data = urlopen(url).read().decode() + # print(data) + data = json_loads(data) + try: + artist = data["author_name"] + title = data["title"].removesuffix(" by " + artist) + except KeyError: + title = "" + artist = "" + return title, artist + + def applemusic_ldjson(self, url): + p = self.parseprop() + data = urlopen(url).read().decode() + p.feed(data) + # print(AppleMusic.ldjson) + data = json_loads(AppleMusic.ldjson) + # print(data) + title = data["name"] + artists = data["audio"]["byArtist"] + artists = [i["name"] for i in artists] + artists = ", ".join(artists[:-1]) + " & " + artists[-1] + return title, artists, data + + def applemusic(self, url): + # self.util.mesg("dbg hello") + url = url.rstrip("\x01") + title = "" + artist = "" + irc_string = "[\x0304AppleMusic\x03] \x0307ERROR:\x0308 got no data from server! \x0315(check your URL for typos!)\x03" + ansi_string = "[\x1b[31mAppleMusic\x1b[0m] \x1b[33;2mERROR:\x1b[33;1m got no data from server! \x1b[37;2m(check your URL for typos!)\x1b[0m" + if self.is_album(url): + title, artist = self.applemusic_oembed(url) + else: + title, artist, data = self.applemusic_ldjson(url) + try: + type = data["@type"] + except KeyError: + print(ansi_string) + return irc_string, True + + if title == "": + print(ansi_string) + return irc_string, True + irc_string = ( + f"[\x0303AppleMusic\x03] \x02{title}\x02 uploaded by \x1d{artist}\x1d" + ) + ansi_string = f"[\x1b[32mAppleMusic\x1b[0m] \x1b[1m{title}\x1b[0m uploaded by \x1b[03m{artist}\x1b[0m" + # """ + # irc_string="dummy";ansi_string="dummy" + print(ansi_string) + return irc_string, False + + +if __name__ == "__main__": + import sys + + # AppleMusic.applemusic(AppleMusic, sys.argv[1]) + AppleMusic().applemusic(sys.argv[1]) diff --git a/bandcamp.py b/bandcamp.py index 29f2b2b..2d76b22 100755 --- a/bandcamp.py +++ b/bandcamp.py @@ -56,9 +56,6 @@ class Bandcamp: irc_string = "[\x0304BandCamp\x03] \x0307ERROR:\x0308 got no data from server! \x0315(check your URL for typos!)\x03" ansi_string = "[\x1b[31mBandCamp\x1b[0m] \x1b[33;2mERROR:\x1b[33;1m got no data from server! \x1b[37;2m(check your URL for typos!)\x1b[0m" data = json.loads(Bandcamp.ldjson) - # print(data) - # for i in data: - # print(i) try: type = data["@type"] except KeyError: @@ -68,11 +65,6 @@ class Bandcamp: name = data["name"] date = data["datePublished"] artists = data["byArtist"]["name"] - # artists=artists.removeprefix(f'Listen to {name} on Spotify').removeprefix('.').strip().removeprefix('· ') - # if artists.startswith("Song · "): artists=artists.removeprefix("Song · ") - # elif artists.startswith("Album · "): - # artists=artists.removeprefix("Album · ")[::-1].split(" · ",1)[1][::-1] #removes the "10 songs" part from album - # artists=artists.removesuffix(f" · {date[:4]}") #remove the year too irc_string = f"[\x0303BandCamp\x03] \x02{name}\x02 by \x1d{artists}\x1d published on {date}" ansi_string = f"[\x1b[32mBandCamp\x1b[0m] \x1b[1m{name}\x1b[0m by \x1b[03m{artists}\x1b[0m published on {date}" # print(("Song: " if type=="MusicRecording" else "Album: " if type=="MusicAlbum" else f"Unknown type ({type}): ")+'"'+name+'"'+" by "+'"'+artists+'"'+" released on "+date) @@ -83,5 +75,5 @@ class Bandcamp: if __name__ == "__main__": import sys - #Bandcamp.bandcamp(Bandcamp, sys.argv[1]) + # Bandcamp.bandcamp(Bandcamp, sys.argv[1]) Bandcamp().bandcamp(sys.argv[1]) diff --git a/soundcloud.py b/soundcloud.py index 4b6e717..7fa6a53 100755 --- a/soundcloud.py +++ b/soundcloud.py @@ -56,5 +56,5 @@ class SoundCloud: if __name__ == "__main__": import sys - #SoundCloud.soundcloud(SoundCloud, sys.argv[1]) + # SoundCloud.soundcloud(SoundCloud, sys.argv[1]) SoundCloud().soundcloud(sys.argv[1]) diff --git a/spotify.py b/spotify.py index fc70f34..e9b0790 100755 --- a/spotify.py +++ b/spotify.py @@ -84,5 +84,5 @@ class Spotify: if __name__ == "__main__": import sys - #Spotify.spotify(Spotify, sys.argv[1]) + # Spotify.spotify(Spotify, sys.argv[1]) Spotify().spotify(sys.argv[1]) diff --git a/test.sh b/test.sh index cbe4f47..ad2942d 100755 --- a/test.sh +++ b/test.sh @@ -20,3 +20,7 @@ ./youtube.py https://www.youtube.com/playlist?list=PL0bbUqXsNHE0ZELST3vW_11GDHKDAwLYh ./youtube.py 'https://www.youtube.com/watch?v=eneLP_P1_fg&list=PL0bbUqXsNHE0ZELST3vW_11GDHKDAwLYh&index=2' ./youtube.py 'https://www.youtube.com/watch?v=I1Dy0Zfw6Qs&list=PLA1IEkclm7_JyTGyYmbT3qId167rGif8I&index=1' + +#apple music oembed only supports albums for SOME reason??? use ld+json for specific songs +./applemusic.py https://music.apple.com/us/album/wishi-wishi-edit-feat-scotts-maphuma-young-stunna-single/1781635613 +./applemusic.py https://music.apple.com/us/song/wishi-wishi-edit-feat-scotts-maphuma-young-stunna/1781635615 diff --git a/youtube.py b/youtube.py index f15613e..1e60546 100755 --- a/youtube.py +++ b/youtube.py @@ -96,6 +96,9 @@ class YouTube: video_id = None try: playlist_id = qs["list"][0] + #ignore the "random mix" and "radio" lists + if playlist_id.startswith("RD"): + playlist_id = None except KeyError: playlist_id = None if (self.prefer_playlist and playlist_id) or (playlist_id and not video_id): @@ -104,7 +107,7 @@ class YouTube: url = url.scheme + "://" + url.netloc + url.path + "?v=" + video_id url = f"https://www.youtube.com/oembed?{urlencode([('url',url),('format','json')])}" try: - #print(url, " and ", playlist_id) + # print(url, " and ", playlist_id) data = urlopen(url).read().decode() data = json_loads(data) title = data["title"] @@ -125,8 +128,8 @@ class YouTube: if __name__ == "__main__": import sys - #if url is a video that's part of a playlist, - #return playlist (True) or video (False, default)? - #YouTube.prefer_playlist=False + # if url is a video that's part of a playlist, + # return playlist (True) or video (False, default)? + # YouTube.prefer_playlist=False YouTube().yt(sys.argv[1]) - #YouTube.yt(YouTube, sys.argv[1]) + # YouTube.yt(YouTube, sys.argv[1]) -- cgit 1.4.1-2-gfad0