Skip to content

Commit

Permalink
Add playlist searching
Browse files Browse the repository at this point in the history
  • Loading branch information
AnonymousX86 committed Nov 11, 2023
1 parent 70478ac commit 22d9151
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 91 deletions.
1 change: 1 addition & 0 deletions Spoyt/embeds/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
GREEN = 0x2ECC71
RED = 0xFF0000
DARK_RED = 0x992D22
GOLD = 0xFFCC00
2 changes: 2 additions & 0 deletions Spoyt/embeds/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ def create_embed(data: EmbedDict) -> BaseDiscordEmbed or BaseGuildedEmbed:
)
if url := data.thumbnail_url:
embed.set_thumbnail(url=url)

return embed
86 changes: 67 additions & 19 deletions Spoyt/embeds/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
from discord import Embed as DiscordEmbed, Color as DiscordColor
from guilded import Embed as GuiledEmbed, Color as GuildedColor

from Spoyt.embeds.color import DEFAULT, DARK_RED, GREEN, RED
from Spoyt.embeds.color import DEFAULT, DARK_RED, GREEN, RED, GOLD
from Spoyt.env_check import is_discord, is_guilded
from Spoyt.spotify_api import Track
from Spoyt.spotify_api import Playlist, Track
from Spoyt.youtube_api import YouTubeResult


MAX_QUERY = 10


class BaseDiscordEmbed(DiscordEmbed):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -40,15 +43,21 @@ def __init__(
title: str = None,
description: str = None,
color: int = DEFAULT,
fields: list[EmbedField] = [],
thumbnail_url: str = None
) -> None:
self.title = title
self.description = description
self.color = color
self.fields = fields
self._fields = []
self.thumbnail_url = thumbnail_url

def add_field(self, name: str, value: str, inline: bool = True) -> None:
self._fields.append(EmbedField(name, value, inline))

@property
def fields(self) -> list[EmbedField]:
return self._fields.copy()


def markdown_url(url: str) -> str:
return (
Expand All @@ -59,23 +68,51 @@ def markdown_url(url: str) -> str:


def track_to_embed(track: Track) -> EmbedDict:
return EmbedDict(
em = EmbedDict(
title=track.name,
description=markdown_url(track.track_url),
color=GREEN,
fields=[
EmbedField(
name='Artist{}'.format('' if track.is_single_artist else 's'),
value=', '.join(track.artists),
inline=track.is_single_artist
),
EmbedField(
name='Released',
value=track.release_date
)
],
thumbnail_url=track.album_url
thumbnail_url=track.cover_url
)
em.add_field(
name='Artist{}'.format('' if track.is_single_artist else 's'),
value=', '.join(track.artists),
inline=track.is_single_artist
)
em.add_field(
name='Released',
value=track.release_date
)
return em


def playlist_to_embed(playlist: Playlist) -> EmbedDict:
if (d := playlist.description):
description = f'{d}\n\n{playlist.url}'
else:
description = playlist.playlist_url
em = EmbedDict(
title=playlist.name,
description=description,
color=GREEN,
thumbnail_url=playlist.cover_url
)
em.add_field(
name='Owner',
value=f'[{playlist.owner_name}]({playlist.owner_url})',
inline=False
)
first_tracks = '\n'.join(map(
lambda a: f'- [{a.name}]({a.track_url})',
playlist.tracks[:MAX_QUERY]
))
if (tr := playlist.total_tracks) > MAX_QUERY:
first_tracks += f'\nAnd {tr - MAX_QUERY} more.'
em.add_field(
name='Tracks',
value=first_tracks
)
return em


def video_to_embed(video: YouTubeResult) -> EmbedDict:
Expand All @@ -101,13 +138,13 @@ def video_to_embed(video: YouTubeResult) -> EmbedDict:
title='\u23f3 Spotify link found!',
description='Connecting to super secret database\u2026',
color=GREEN
),
)

SPOTIFY_UNREACHABLE = EmbedDict(
title='Oh no',
description='Spotify is out of service',
color=RED
),
)

SEARCHING_YOUTUBE = EmbedDict(
title='\u23f3 Searching YouTube'
Expand All @@ -117,3 +154,14 @@ def video_to_embed(video: YouTubeResult) -> EmbedDict:
title='Video not found',
color=DARK_RED
)

FUNCTION_NOT_AVAILABLE = EmbedDict(
title='\u274c Function is currently unavailable',
color=DARK_RED
)

FUNCTION_IN_DEVELOPMENT = EmbedDict(
title='\U0001f6e0 Function is under construction',
description='Please check debug console for output',
color=GOLD
)
77 changes: 50 additions & 27 deletions Spoyt/spotify_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,68 @@


class Track:
def __init__(
self,
name: str,
track_id: str,
artists: list[str],
release_date: str,
album_url: str
):
self.name: str = name
self.track_id: str = track_id
self.artists: list[str] = artists
self.release_date: str = release_date
self.album_url: str = album_url
def __init__(self, payload: dict) -> None:
self.name: str = payload.get('name')
self.track_id: str = payload.get('id')
self.artists: list[str] = list(map(
lambda a: a.get('name'),
payload.get('artists', {})
))
self.release_date: str = payload.get('album', {}).get('release_date')
self.cover_url: str = payload.get('album', {}).get('images', [{}])[0].get('url')

@property
def is_single_artist(self):
def is_single_artist(self) -> bool:
return len(self.artists) == 1

@property
def track_url(self):
def track_url(self) -> str:
return f'https://open.spotify.com/track/{self.track_id}'

class Playlist:
def __init__(self, payload: dict) -> None:
self.name: str = payload.get('name')
self.description: str = payload.get('description')
self.playlist_id: str = payload.get('id')
self.owner_name: str = payload.get('owner', {}).get('display_name')
self.owner_id: str = payload.get('owner', {}).get('id')
self.cover_url: str = payload.get('images', [{}])[0].get('url')
self.tracks: list[Track] = list(map(
lambda a: Track(a.get('track', {})),
payload.get('tracks', {}).get('items')
))
self.total_tracks: int = payload.get('tracks', {}).get('total')
self.query_limit: int = payload.get('tracks', {}).get('limit')

def model_track(track: dict) -> Track:
return Track(
name=track['name'],
track_id=track['id'],
artists=list(map(lambda a: a['name'], track['artists'])),
release_date=track['album']['release_date'],
album_url=track['album']['images'][0]['url']
)
@property
def playlist_url(self) -> str:
return f'https://open.spotify.com/playlist/{self.playlist_id}'

@property
def owner_url(self) -> str:
return f'https://open.spotify.com/user/{self.owner_id}'

@property
def is_query_limited(self) -> bool:
return len(self.tracks) == self.query_limit


def search_spotify(track_id: str) -> dict:
log.info(f'Searching ID "{track_id}"')
spotify = Spotify(
def spotify_connect() -> Spotify:
return Spotify(
auth_manager=SpotifyClientCredentials(
client_id=getenv('SPOTIFY_CLIENT_ID'),
client_secret=getenv('SPOTIFY_CLIENT_SECRET')
)
)
return spotify.track(track_id=track_id)

# Search functions should not return `class Track` or `class Playlist`
# because of checks if connections was successful during runtime.

def search_track(track_id: str) -> dict:
log.info(f'Searching track by ID "{track_id}"')
return spotify_connect().track(track_id=track_id)


def search_playlist(playlist_id: str) -> dict:
log.info(f'Searching playlist by ID "{playlist_id}"')
return spotify_connect().playlist(playlist_id=playlist_id)
Loading

0 comments on commit 22d9151

Please sign in to comment.