-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,10 @@ | ||
# spoyt | ||
Spotify to YouTube Discord link converter | ||
# Spoyt | ||
|
||
Spotify to YouTube Discord link converter | ||
|
||
## Usage | ||
|
||
Just send a message with share link from Spotify. Bot will automatically find | ||
the track in Spotify database, and search its name and artists in YouTube. | ||
If possible, bit will try to delete your message, but you can disable it | ||
by permitting it by permissions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# -*- coding: utf-8 -*- | ||
from os import getenv | ||
|
||
from discord import Client, Intents, Message, Embed, Color, \ | ||
ActivityType, Activity, NotFound, Forbidden | ||
|
||
from Spoyt.spotify_api import search_spotify, model_track, TrackEmbed | ||
from Spoyt.youtube_api import create_youtube, search_youtube | ||
|
||
|
||
def main(): | ||
intents = Intents.default() | ||
intents.message_content = True | ||
|
||
client = Client(intents=intents) | ||
client.youtube = None | ||
|
||
@client.event | ||
async def on_ready(): | ||
print(f'Logged in as {client.user}') | ||
await client.change_presence( | ||
activity=Activity( | ||
name='Spotify & YouTube', | ||
type=ActivityType.listening | ||
) | ||
) | ||
client.youtube = create_youtube() | ||
|
||
@client.event | ||
async def on_message(message: Message): | ||
if not message.content.startswith('https://open.spotify.com/track/'): | ||
return | ||
|
||
msg = await message.channel.send(embed=Embed( | ||
title=':hourglass_flowing_sand: Spotify link found!', | ||
description='Connecting to super secret database...', | ||
color=Color.green() | ||
)) | ||
|
||
track_id = message.content.split('?')[0].split('&')[0].split('/')[-1] | ||
spotify_query = search_spotify(track_id) | ||
|
||
if not spotify_query: | ||
await msg.edit(embed=Embed( | ||
title='Oh no', | ||
description='Spotify is out of service', | ||
color=Color.red() | ||
)) | ||
return | ||
|
||
track = model_track(spotify_query) | ||
track_embed = TrackEmbed(track) | ||
|
||
try: | ||
await message.delete() | ||
except Forbidden or NotFound: | ||
pass | ||
else: | ||
track_embed.add_author(message.author) | ||
|
||
await msg.edit(embeds=[track_embed, Embed( | ||
title=':hourglass_flowing_sand: Searching YouTube', | ||
color=Color.blurple() | ||
)]) | ||
|
||
video_id = search_youtube( | ||
youtube=client.youtube, | ||
query='{} {}'.format(track.name, ' '.join(track.artists)) | ||
) | ||
|
||
await msg.edit(embeds=[track_embed, Embed( | ||
title='Best YouTube result', | ||
color=Color.blurple() | ||
)]) | ||
|
||
await message.channel.send( | ||
content=f'https://www.youtube.com/watch?v={video_id}' | ||
) | ||
|
||
client.run(getenv('BOT_TOKEN')) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# -*- coding: utf-8 -*- | ||
from os import getenv | ||
|
||
from discord import Embed, Color, Member | ||
from spotipy import Spotify, SpotifyClientCredentials | ||
|
||
|
||
class Track: | ||
def __init__( | ||
self, | ||
name: str, | ||
track_id: str, | ||
artists: str or list[str], | ||
release_date: str, | ||
album_url: str | ||
): | ||
self.name = name | ||
self.track_id = track_id | ||
self.artists = artists | ||
self.release_date = release_date | ||
self.album_url = album_url | ||
|
||
@property | ||
def is_single_artist(self): | ||
return len(self.artists) > 1 | ||
|
||
@property | ||
def track_url(self): | ||
return f'https://open.spotify.com/track/{self.track_id}' | ||
|
||
|
||
class TrackEmbed(Embed): | ||
def __init__(self, track: Track): | ||
super().__init__() | ||
self.title = track.name | ||
self.description = f'<{track.track_url}>' | ||
self.color = Color.green() | ||
self.add_field( | ||
name='Artist{}'.format( | ||
'' if track.is_single_artist else 's'), | ||
value=', '.join(track.artists), | ||
inline=track.is_single_artist | ||
).add_field( | ||
name='Released', | ||
value=track.release_date | ||
).set_thumbnail( | ||
url=track.album_url | ||
) | ||
|
||
def add_author(self, author: Member): | ||
self.set_author( | ||
name=f'{author.display_name} shared:', | ||
icon_url=author.display_avatar.url | ||
) | ||
|
||
|
||
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'] | ||
) | ||
|
||
|
||
def search_spotify(track_id: str) -> dict: | ||
spotify = Spotify( | ||
auth_manager=SpotifyClientCredentials( | ||
client_id=getenv('SPOTIFY_CLIENT_ID'), | ||
client_secret=getenv('SPOTIFY_CLIENT_SECRET') | ||
) | ||
) | ||
return spotify.track(track_id=track_id) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# -*- coding: utf-8 -*- | ||
from os import getenv | ||
|
||
import google_auth_oauthlib.flow | ||
import googleapiclient.discovery | ||
|
||
|
||
def create_youtube() -> googleapiclient.discovery: | ||
flow = google_auth_oauthlib.flow.InstalledAppFlow. \ | ||
from_client_secrets_file( | ||
getenv('YOUTUBE_CLIENT_SECRET_FILE'), | ||
['https://www.googleapis.com/auth/youtube.force-ssl'] | ||
) | ||
credentials = flow.run_local_server() | ||
youtube = googleapiclient.discovery.build( | ||
'youtube', | ||
'v3', | ||
credentials=credentials | ||
) | ||
return youtube | ||
|
||
|
||
def search_youtube(youtube: googleapiclient.discovery, query: str) -> str: | ||
yt_req = youtube.search().list( | ||
part='snippet', | ||
maxResults=1, | ||
q=query, | ||
type='video' | ||
) | ||
yt_res = yt_req.execute() | ||
return yt_res['items'][0]['id']['videoId'] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
discord.py | ||
requests | ||
google-api-python-client | ||
google-auth-oauthlib | ||
google-auth-httplib2 | ||
spotipy |