Skip to content

Commit

Permalink
extract main
Browse files Browse the repository at this point in the history
  • Loading branch information
sigma67 committed Apr 7, 2023
1 parent b10bfa6 commit b227ce1
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 98 deletions.
38 changes: 30 additions & 8 deletions spotify_to_ytmusic/Setup.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
import sys
import settings

if __name__ == "__main__":
if sys.argv[1] == "youtube":
from ytmusicapi import YTMusic
api = YTMusic()
settings['youtube']['headers'] = api.setup()
settings.save()

from settings import Settings
import ytmusicapi

settings = Settings()

def setup():
choice = input("Choose which API to set up\n"
"(1) Spotify\n"
"(2) YouTube\n"
"(3) both")
choices = ["1","2","3"]
if choice not in choices:
sys.exit("Invalid choice")

if choice == choices[0]:
setup_spotify()
elif choice == choices[1]:
setup_youtube()
else:
setup_spotify()
setup_youtube()

def setup_youtube():
settings['youtube']['headers'] = ytmusicapi.setup_oauth()
settings.save()

def setup_spotify():
pass
#settings['spotipy']
3 changes: 2 additions & 1 deletion spotify_to_ytmusic/SpotifyExport.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ def __init__(self):
def getSpotifyPlaylist(self, url):
playlistId = get_id_from_url(url)
if len(playlistId) != 22:
raise Exception('Bad playlist id: ' + playlistId)
raise Exception(f'Bad playlist id: {playlistId}')

print("Getting Spotify tracks...")
results = self.api.playlist(playlistId)
name = results['name']
total = int(results['tracks']['total'])
Expand Down
76 changes: 2 additions & 74 deletions spotify_to_ytmusic/YouTube.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
from ytmusicapi import YTMusic
from datetime import datetime
import os
import re
import argparse
import difflib
from collections import OrderedDict
from SpotifyExport import Spotify
import settings

path = os.path.dirname(os.path.realpath(__file__)) + os.sep
Expand Down Expand Up @@ -50,12 +47,11 @@ def get_best_fit_song_id(self, results, song):
if res['resultType'] == 'song' and res['album'] is not None:
scores.append(difflib.SequenceMatcher(a=res['album']['name'].lower(), b=song['album'].lower()).ratio())

match_score[res['videoId']] = sum(scores) / len(scores) * max(1, int(res['resultType'] == 'song') * 1.5)
match_score[res['videoId']] = sum(scores) / len(scores) * max(1, int(res['resultType'] == 'song') * 2)

if len(match_score) == 0:
return None

#don't return songs with titles <45% match
max_score = max(match_score, key=match_score.get)
return max_score

Expand All @@ -77,6 +73,7 @@ def search_songs(self, tracks):
else:
videoIds.append(targetSong)

print("Searching YouTube...")
if i > 0 and i % 10 == 0:
print(f"YouTube tracks: {i}/{len(songs)}")

Expand Down Expand Up @@ -119,72 +116,3 @@ def remove_playlists(self, pattern):
else:
print("Aborted. No playlists were deleted.")


def get_args():
parser = argparse.ArgumentParser(description='Transfer spotify playlist to YouTube Music.')
parser.add_argument("playlist", type=str, help="Provide a playlist Spotify link.")
parser.add_argument("-u", "--update", action='store_true', help="Delete all entries in the provided Google Play Music playlist and update the playlist with entries from the Spotify playlist.")
parser.add_argument("-n", "--name", type=str, help="Provide a name for the YouTube Music playlist. Default: Spotify playlist name")
parser.add_argument("-i", "--info", type=str, help="Provide description information for the YouTube Music Playlist. Default: Spotify playlist description")
parser.add_argument("-d", "--date", action='store_true', help="Append the current date to the playlist name")
parser.add_argument("-p", "--public", action='store_true', help="Make the playlist public. Default: private")
parser.add_argument("-r", "--remove", action='store_true', help="Remove playlists with specified regex pattern.")
parser.add_argument("-a", "--all", action='store_true', help="Transfer all public playlists of the specified user (Spotify User ID).")
return parser.parse_args()


def main():
args = get_args()
ytmusic = YTMusicTransfer()

if args.all:
s = Spotify()
pl = s.getUserPlaylists(args.playlist)
print(str(len(pl)) + " playlists found. Starting transfer...")
count = 1
for p in pl:
print("Playlist " + str(count) + ": " + p['name'])
count = count + 1
try:
playlist = Spotify().getSpotifyPlaylist(p['external_urls']['spotify'])
videoIds = ytmusic.search_songs(playlist['tracks'])
playlist_id = ytmusic.create_playlist(p['name'], p['description'],
'PUBLIC' if args.public else 'PRIVATE',
videoIds)
print(playlist_id)
except Exception as ex:
print("Could not transfer playlist " + p['name'] + ". Exception" + str(ex))
return

if args.remove:
ytmusic.remove_playlists(args.playlist)
return

date = ""
if args.date:
date = " " + datetime.today().strftime('%m/%d/%Y')
try:
playlist = Spotify().getSpotifyPlaylist(args.playlist)
except Exception as ex:
print("Could not get Spotify playlist. Please check the playlist link.\n Error: " + repr(ex))
return

name = args.name + date if args.name else playlist['name'] + date
info = playlist['description'] if (args.info is None) else args.info

if args.update:
playlistId = ytmusic.get_playlist_id(name)
videoIds = ytmusic.search_songs(playlist['tracks'])
ytmusic.remove_songs(playlistId)
ytmusic.add_playlist_items(playlistId, videoIds)

else:
videoIds = ytmusic.search_songs(playlist['tracks'])
playlistId = ytmusic.create_playlist(name, info, 'PUBLIC' if args.public else 'PRIVATE', videoIds)

print("Success: created playlist \"" + name + "\"\n" +
"https://music.youtube.com/playlist?list=" + playlistId)


if __name__ == "__main__":
main()
82 changes: 82 additions & 0 deletions spotify_to_ytmusic/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import argparse
import sys
from datetime import datetime

from spotify_to_ytmusic.Setup import setup
from spotify_to_ytmusic.SpotifyExport import Spotify
from spotify_to_ytmusic.YouTube import YTMusicTransfer


def get_args():
parser = argparse.ArgumentParser(description='Transfer spotify playlist to YouTube Music.')
parser.add_argument("playlist", type=str, help="Provide a playlist Spotify link.")
parser.add_argument("-u", "--update", action='store_true', help="Delete all entries in the provided Google Play Music playlist and update the playlist with entries from the Spotify playlist.")
parser.add_argument("-n", "--name", type=str, help="Provide a name for the YouTube Music playlist. Default: Spotify playlist name")
parser.add_argument("-i", "--info", type=str, help="Provide description information for the YouTube Music Playlist. Default: Spotify playlist description")
parser.add_argument("-d", "--date", action='store_true', help="Append the current date to the playlist name")
parser.add_argument("-p", "--public", action='store_true', help="Make the playlist public. Default: private")
parser.add_argument("-r", "--remove", action='store_true', help="Remove playlists with specified regex pattern.")
parser.add_argument("-a", "--all", action='store_true', help="Transfer all public playlists of the specified user (Spotify User ID).")
parser.add_argument("--setup", help="Set up credentials")
return parser.parse_args()


def main():
args = get_args()
ytmusic = YTMusicTransfer()

if args.setup:
setup()
sys.exit()

if args.all:
s = Spotify()
pl = s.getUserPlaylists(args.playlist)
print(str(len(pl)) + " playlists found. Starting transfer...")
count = 1
for p in pl:
print("Playlist " + str(count) + ": " + p['name'])
count = count + 1
try:
playlist = Spotify().getSpotifyPlaylist(p['external_urls']['spotify'])
videoIds = ytmusic.search_songs(playlist['tracks'])
playlist_id = ytmusic.create_playlist(p['name'], p['description'],
'PUBLIC' if args.public else 'PRIVATE',
videoIds)
print(playlist_id)
except Exception as ex:
print("Could not transfer playlist " + p['name'] + ". Exception" + str(ex))
return

if args.remove:
ytmusic.remove_playlists(args.playlist)
return

date = ""
if args.date:
date = " " + datetime.today().strftime('%m/%d/%Y')
try:
playlist = Spotify().getSpotifyPlaylist(args.playlist)
except Exception as ex:
print("Could not get Spotify playlist. Please check the playlist link.\n Error: " + repr(ex))
return

name = args.name + date if args.name else playlist['name'] + date
info = playlist['description'] if (args.info is None) else args.info

if args.update:
playlistId = ytmusic.get_playlist_id(name)
videoIds = ytmusic.search_songs(playlist['tracks'])
ytmusic.remove_songs(playlistId)
ytmusic.add_playlist_items(playlistId, videoIds)

else:
videoIds = ytmusic.search_songs(playlist['tracks'])
playlistId = ytmusic.create_playlist(name, info, 'PUBLIC' if args.public else 'PRIVATE', videoIds)

print("Success: created playlist \"" + name + "\"\n" +
"https://music.youtube.com/playlist?list=" + playlistId)


if __name__ == "__main__":
main()
27 changes: 12 additions & 15 deletions spotify_to_ytmusic/settings.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import configparser
import sys
import types
import os
from pathlib import Path
from typing import Optional

config = configparser.ConfigParser(interpolation=None)
filepath = os.path.dirname(os.path.realpath(__file__)) + '/settings.ini'
config.read(filepath)

class Settings:

class Settings(types.ModuleType):
config: configparser.ConfigParser
def __init__(self, filepath: Optional[Path] = None):
self.config = configparser.ConfigParser(interpolation=None)
self.filepath = filepath if filepath else Path(__file__).parent.joinpath('settings.ini')
self.config.read(self.filepath)

def __getitem__(self, key):
return config[key]
return self.config[key]

def __setitem__(self, section, key, value):
config.set(section, key, value)
self.config.set(section, key, value)

def save(self):
with open(filepath, 'w') as f:
config.write(f)



sys.modules[__name__] = Settings("settings")
with open(self.filepath, 'w') as f:
self.config.write(f)

0 comments on commit b227ce1

Please sign in to comment.