diff --git a/build/lib/pomice/__init__.py b/build/lib/pomice/__init__.py deleted file mode 100644 index d0fd69c..0000000 --- a/build/lib/pomice/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Pomice -~~~~~~ -The modern Lavalink wrapper designed for discord.py. - -:copyright: 2023, cloudwithax -:license: GPL-3.0 -""" -import discord - -if not discord.version_info.major >= 2: - class DiscordPyOutdated(Exception): - pass - - raise DiscordPyOutdated( - "You must have discord.py (v2.0 or greater) to use this library. " - "Uninstall your current version and install discord.py 2.0 " - "using 'pip install discord.py'" - ) - -__version__ = "2.1.1" -__title__ = "pomice" -__author__ = "cloudwithax" - -from .enums import * -from .events import * -from .exceptions import * -from .filters import * -from .objects import * -from .queue import * -from .player import * -from .pool import * -from .routeplanner import * - diff --git a/build/lib/pomice/applemusic/__init__.py b/build/lib/pomice/applemusic/__init__.py deleted file mode 100644 index 1c9005c..0000000 --- a/build/lib/pomice/applemusic/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Apple Music module for Pomice, made possible by cloudwithax 2023""" - -from .exceptions import * -from .objects import * -from .client import Client \ No newline at end of file diff --git a/build/lib/pomice/applemusic/client.py b/build/lib/pomice/applemusic/client.py deleted file mode 100644 index e0b00b3..0000000 --- a/build/lib/pomice/applemusic/client.py +++ /dev/null @@ -1,124 +0,0 @@ -import re -import aiohttp -import orjson as json -import base64 - -from datetime import datetime -from .objects import * -from .exceptions import * - -AM_URL_REGEX = re.compile(r"https?://music.apple.com/(?P[a-zA-Z]{2})/(?Palbum|playlist|song|artist)/(?P.+)/(?P[^?]+)") -AM_SINGLE_IN_ALBUM_REGEX = re.compile(r"https?://music.apple.com/(?P[a-zA-Z]{2})/(?Palbum|playlist|song|artist)/(?P.+)/(?P.+)(\?i=)(?P.+)") -AM_REQ_URL = "https://api.music.apple.com/v1/catalog/{country}/{type}s/{id}" -AM_BASE_URL = "https://api.music.apple.com" - -class Client: - """The base Apple Music client for Pomice. - This will do all the heavy lifting of getting tracks from Apple Music - and translating it to a valid Lavalink track. No client auth is required here. - """ - - def __init__(self) -> None: - self.token: str = None - self.expiry: datetime = None - self.session: aiohttp.ClientSession = aiohttp.ClientSession() - self.headers = None - - - async def request_token(self): - async with self.session.get("https://music.apple.com/assets/index.919fe17f.js") as resp: - if resp.status != 200: - raise AppleMusicRequestException( - f"Error while fetching results: {resp.status} {resp.reason}" - ) - text = await resp.text() - result = re.search("\"(eyJ.+?)\"", text).group(1) - self.token = result - self.headers = { - 'Authorization': f"Bearer {result}", - 'Origin': 'https://apple.com', - } - token_split = self.token.split(".")[1] - token_json = base64.b64decode(token_split + '=' * (-len(token_split) % 4)).decode() - token_data = json.loads(token_json) - self.expiry = datetime.fromtimestamp(token_data["exp"]) - - - async def search(self, query: str): - if not self.token or datetime.utcnow() > self.expiry: - await self.request_token() - - result = AM_URL_REGEX.match(query) - - country = result.group("country") - type = result.group("type") - id = result.group("id") - - if type == "album" and (sia_result := AM_SINGLE_IN_ALBUM_REGEX.match(query)): - # apple music likes to generate links for singles off an album - # by adding a param at the end of the url - # so we're gonna scan for that and correct it - id = sia_result.group("id2") - type = "song" - request_url = AM_REQ_URL.format(country=country, type=type, id=id) - else: - request_url = AM_REQ_URL.format(country=country, type=type, id=id) - - - async with self.session.get(request_url, headers=self.headers) as resp: - if resp.status != 200: - raise AppleMusicRequestException( - f"Error while fetching results: {resp.status} {resp.reason}" - ) - data: dict = await resp.json(loads=json.loads) - - data = data["data"][0] - - - if type == "song": - return Song(data) - - elif type == "album": - return Album(data) - - elif type == "artist": - async with self.session.get(f"{request_url}/view/top-songs", headers=self.headers) as resp: - if resp.status != 200: - raise AppleMusicRequestException( - f"Error while fetching results: {resp.status} {resp.reason}" - ) - top_tracks: dict = await resp.json(loads=json.loads) - tracks: dict = top_tracks["data"] - - return Artist(data, tracks=tracks) - - else: - - track_data: dict = data["relationships"]["tracks"] - - tracks = [Song(track) for track in track_data.get("data")] - - if not len(tracks): - raise AppleMusicRequestException("This playlist is empty and therefore cannot be queued.") - - if track_data.get("next"): - next_page_url = AM_BASE_URL + track_data.get("next") - - while next_page_url is not None: - async with self.session.get(next_page_url, headers=self.headers) as resp: - if resp.status != 200: - raise AppleMusicRequestException( - f"Error while fetching results: {resp.status} {resp.reason}" - ) - - next_data: dict = await resp.json(loads=json.loads) - - tracks += [Song(track) for track in next_data["data"]] - if next_data.get("next"): - next_page_url = AM_BASE_URL + next_data.get("next") - else: - next_page_url = None - - - - return Playlist(data, tracks) \ No newline at end of file diff --git a/build/lib/pomice/applemusic/exceptions.py b/build/lib/pomice/applemusic/exceptions.py deleted file mode 100644 index f9c1f7d..0000000 --- a/build/lib/pomice/applemusic/exceptions.py +++ /dev/null @@ -1,8 +0,0 @@ -class AppleMusicRequestException(Exception): - """An error occurred when making a request to the Apple Music API""" - pass - - -class InvalidAppleMusicURL(Exception): - """An invalid Apple Music URL was passed""" - pass diff --git a/build/lib/pomice/applemusic/objects.py b/build/lib/pomice/applemusic/objects.py deleted file mode 100644 index c7cd7c1..0000000 --- a/build/lib/pomice/applemusic/objects.py +++ /dev/null @@ -1,87 +0,0 @@ -"""Module for managing Apple Music objects""" - -from typing import List - - -class Song: - """The base class for an Apple Music song""" - def __init__(self, data: dict) -> None: - - self.name: str = data["attributes"]["name"] - self.url: str = data["attributes"]["url"] - self.isrc: str = data["attributes"]["isrc"] - self.length: float = data["attributes"]["durationInMillis"] - self.id: str = data["id"] - self.artists: str = data["attributes"]["artistName"] - self.image: str = data["attributes"]["artwork"]["url"].replace( - "{w}x{h}", - f'{data["attributes"]["artwork"]["width"]}x{data["attributes"]["artwork"]["height"]}' - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - -class Playlist: - """The base class for an Apple Music playlist""" - def __init__(self, data: dict, tracks: List[Song]) -> None: - self.name: str = data["attributes"]["name"] - self.owner: str = data["attributes"]["curatorName"] - self.id: str = data["id"] - self.tracks: List[Song] = tracks - self.total_tracks: int = len(tracks) - self.url: str = data["attributes"]["url"] - # we'll use the first song's image as the image for the playlist - # because apple dynamically generates playlist covers client-side - self.image = self.tracks[0].image - - def __repr__(self) -> str: - return ( - f"" - ) - - -class Album: - """The base class for an Apple Music album""" - def __init__(self, data: dict) -> None: - self.name: str = data["attributes"]["name"] - self.url: str = data["attributes"]["url"] - self.id: str = data["id"] - self.artists: str = data["attributes"]["artistName"] - self.total_tracks: int = data["attributes"]["trackCount"] - self.tracks: List[Song] = [Song(track) for track in data["relationships"]["tracks"]["data"]] - self.image: str = data["attributes"]["artwork"]["url"].replace( - "{w}x{h}", - f'{data["attributes"]["artwork"]["width"]}x{data["attributes"]["artwork"]["height"]}' - ) - - def __repr__(self) -> str: - return ( - f"" - ) - - - -class Artist: - """The base class for an Apple Music artist""" - def __init__(self, data: dict, tracks: dict) -> None: - self.name: str = f'Top tracks for {data["attributes"]["name"]}' - self.url: str = data["attributes"]["url"] - self.id: str = data["id"] - self.genres: str = ", ".join(genre for genre in data["attributes"]["genreNames"]) - self.tracks: List[Song] = [Song(track) for track in tracks] - self.image: str = data["attributes"]["artwork"]["url"].replace( - "{w}x{h}", - f'{data["attributes"]["artwork"]["width"]}x{data["attributes"]["artwork"]["height"]}' - ) - - def __repr__(self) -> str: - return ( - f"" - ) \ No newline at end of file diff --git a/build/lib/pomice/enums.py b/build/lib/pomice/enums.py deleted file mode 100644 index 54217b3..0000000 --- a/build/lib/pomice/enums.py +++ /dev/null @@ -1,260 +0,0 @@ -import re - -from enum import Enum - - -class SearchType(Enum): - """ - The enum for the different search types for Pomice. - This feature is exclusively for the Spotify search feature of Pomice. - If you are not using this feature, this class is not necessary. - - SearchType.ytsearch searches using regular Youtube, - which is best for all scenarios. - - SearchType.ytmsearch searches using YouTube Music, - which is best for getting audio-only results. - - SearchType.scsearch searches using SoundCloud, - which is an alternative to YouTube or YouTube Music. - """ - ytsearch = "ytsearch" - ytmsearch = "ytmsearch" - scsearch = "scsearch" - - def __str__(self) -> str: - return self.value - - -class TrackType(Enum): - """ - The enum for the different track types for Pomice. - - TrackType.YOUTUBE defines that the track is from YouTube - - TrackType.SOUNDCLOUD defines that the track is from SoundCloud. - - TrackType.SPOTIFY defines that the track is from Spotify - - TrackType.APPLE_MUSIC defines that the track is from Apple Music. - - TrackType.HTTP defines that the track is from an HTTP source. - """ - - # We don't have to define anything special for these, since these just serve as flags - YOUTUBE = "youtube_track" - SOUNDCLOUD = "soundcloud_track" - SPOTIFY = "spotify_track" - APPLE_MUSIC = "apple_music_track" - HTTP = "http_source" - - def __str__(self) -> str: - return self.value - -class PlaylistType(Enum): - """ - The enum for the different playlist types for Pomice. - - PlaylistType.YOUTUBE defines that the playlist is from YouTube - - PlaylistType.SOUNDCLOUD defines that the playlist is from SoundCloud. - - PlaylistType.SPOTIFY defines that the playlist is from Spotify - - PlaylistType.APPLE_MUSIC defines that the playlist is from Apple Music. - """ - - # We don't have to define anything special for these, since these just serve as flags - YOUTUBE = "youtube_playlist" - SOUNDCLOUD = "soundcloud_playlist" - SPOTIFY = "spotify_playlist" - APPLE_MUSIC = "apple_music_list" - - def __str__(self) -> str: - return self.value - - - -class NodeAlgorithm(Enum): - """ - The enum for the different node algorithms in Pomice. - - The enums in this class are to only differentiate different - methods, since the actual method is handled in the - get_best_node() method. - - NodeAlgorithm.by_ping returns a node based on it's latency, - preferring a node with the lowest response time - - - NodeAlgorithm.by_players return a nodes based on how many players it has. - This algorithm prefers nodes with the least amount of players. - """ - - # We don't have to define anything special for these, since these just serve as flags - by_ping = "BY_PING" - by_players = "BY_PLAYERS" - - def __str__(self) -> str: - return self.value - -class LoopMode(Enum): - """ - The enum for the different loop modes. - This feature is exclusively for the queue utility of pomice. - If you are not using this feature, this class is not necessary. - - LoopMode.TRACK sets the queue loop to the current track. - - LoopMode.QUEUE sets the queue loop to the whole queue. - - """ - # We don't have to define anything special for these, since these just serve as flags - TRACK = "track" - QUEUE = "queue" - - - def __str__(self) -> str: - return self.value - -class PlatformRecommendation(Enum): - - """ - The enum for choosing what platform you want for recommendations. - This feature is exclusively for the recommendations function. - If you are not using this feature, this class is not necessary. - - PlatformRecommendation.SPOTIFY sets the recommendations to come from Spotify - - PlatformRecommendation.YOUTUBE sets the recommendations to come from YouTube - - """ - - # We don't have to define anything special for these, since these just serve as flags - SPOTIFY = "spotify" - YOUTUBE = "youtube" - - - def __str__(self) -> str: - return self.value - - -class RouteStrategy(Enum): - """ - The enum for specifying the route planner strategy for Lavalink. - This feature is exclusively for the RoutePlanner class. - If you are not using this feature, this class is not necessary. - - RouteStrategy.ROTATE_ON_BAN specifies that the node is rotating IPs - whenever they get banned by Youtube. - - RouteStrategy.LOAD_BALANCE specifies that the node is selecting - random IPs to balance out requests between them. - - RouteStrategy.NANO_SWITCH specifies that the node is switching - between IPs every CPU clock cycle. - - RouteStrategy.ROTATING_NANO_SWITCH specifies that the node is switching - between IPs every CPU clock cycle and is rotating between IP blocks on - ban. - - """ - - ROTATE_ON_BAN = "RotatingIpRoutePlanner" - LOAD_BALANCE = "BalancingIpRoutePlanner" - NANO_SWITCH = "NanoIpRoutePlanner" - ROTATING_NANO_SWITCH = "RotatingNanoIpRoutePlanner" - - -class RouteIPType(Enum): - """ - The enum for specifying the route planner IP block type for Lavalink. - This feature is exclusively for the RoutePlanner class. - If you are not using this feature, this class is not necessary. - - RouteIPType.IPV4 specifies that the IP block type is IPV4 - - RouteIPType.IPV6 specifies that the IP block type is IPV6 - """ - - IPV4 = "Inet4Address" - IPV6 = "Inet6Address" - - -class URLRegex(): - """ - The enums for all the URL Regexes in use by Pomice. - - URLRegex.SPOTIFY_URL returns the Spotify URL Regex. - - URLRegex.DISCORD_MP3_URL returns the Discord MP3 URL Regex. - - URLRegex.YOUTUBE_URL returns the Youtube URL Regex. - - URLRegex.YOUTUBE_PLAYLIST returns the Youtube Playlist Regex. - - URLRegex.YOUTUBE_TIMESTAMP returns the Youtube Timestamp Regex. - - URLRegex.AM_URL returns the Apple Music URL Regex. - - URLRegex.SOUNDCLOUD_URL returns the SoundCloud URL Regex. - - URLRegex.BASE_URL returns the standard URL Regex. - - """ - SPOTIFY_URL = re.compile( - r"https?://open.spotify.com/(?Palbum|playlist|track|artist)/(?P[a-zA-Z0-9]+)" - ) - - DISCORD_MP3_URL = re.compile( - r"https?://cdn.discordapp.com/attachments/(?P[0-9]+)/" - r"(?P[0-9]+)/(?P[a-zA-Z0-9_.]+)+" - ) - - YOUTUBE_URL = re.compile( - r"^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))" - r"(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$" - ) - - YOUTUBE_PLAYLIST_URL = re.compile( - r"^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))/playlist\?list=.*" - ) - - YOUTUBE_VID_IN_PLAYLIST = re.compile( - r"(?P