Skip to content

Commit

Permalink
feat: Add ytmusicapi browser auth setup option (#117)
Browse files Browse the repository at this point in the history
* feat: Add ytmusicapi browser auth setup option

Added doc for browser auth

* fix: Ask for api re-authorization on playlist creation if using browser

Remove unecessary line from settings save method
  • Loading branch information
rpop0 authored Nov 23, 2024
1 parent f2f0b25 commit 04d0084
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 6 deletions.
1 change: 1 addition & 0 deletions spotify_to_ytmusic/settings.ini.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[youtube]
headers = headers_json_from_browser
user_id =
auth_type = browser

[spotify]
client_id = id_from_developer_console
Expand Down
16 changes: 14 additions & 2 deletions spotify_to_ytmusic/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ def setup(file: Optional[Path] = None):

if not DEFAULT_PATH.is_file():
shutil.copy(EXAMPLE_PATH, DEFAULT_PATH)
choice = input("Choose which API to set up\n" "(1) Spotify\n" "(2) YouTube\n" "(3) both\n")
choices = ["1", "2", "3"]
choice = input("Choose which API to set up\n(1) Spotify\n(2) YouTube (oAuth)\n(3) Youtube (Browser)\n(4) both \n")

choices = ["1", "2", "3", "4"]
if choice not in choices:
sys.exit("Invalid choice")

Expand All @@ -27,6 +28,8 @@ def setup(file: Optional[Path] = None):
elif choice == choices[1]:
setup_youtube()
elif choice == choices[2]:
setup_youtube_browser()
elif choice == choices[3]:
setup_spotify()
setup_youtube()

Expand All @@ -35,6 +38,15 @@ def setup_youtube():
settings = Settings()
credentials = ytmusicapi.setup_oauth(open_browser=has_browser())
settings["youtube"]["headers"] = json.dumps(credentials.as_dict())
settings["youtube"]["auth_type"] = "oauth"
settings.save()

def setup_youtube_browser():
settings = Settings()
print('Please see https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html for instructions.')
credentials = ytmusicapi.setup()
settings["youtube"]["headers"] = credentials
settings["youtube"]["auth_type"] = "browser"
settings.save()


Expand Down
11 changes: 8 additions & 3 deletions spotify_to_ytmusic/ytmusic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@

from spotify_to_ytmusic.utils.match import get_best_fit_song_id
from spotify_to_ytmusic.settings import Settings
from spotify_to_ytmusic.setup import setup_youtube_browser

path = os.path.dirname(os.path.realpath(__file__)) + os.sep


class YTMusicTransfer:
def __init__(self):
settings = Settings()
headers = settings["youtube"]["headers"]
self.settings = Settings()
headers = self.settings["youtube"]["headers"]
assert headers.startswith("{"), "ytmusicapi headers not set or invalid"
self.api = YTMusic(headers, settings["youtube"]["user_id"])
self.api = YTMusic(headers, self.settings["youtube"]["user_id"])

def create_playlist(self, name, info, privacy="PRIVATE", tracks=None):
if self.settings["youtube"]["auth_type"] == "browser":
setup_youtube_browser()
self.api = YTMusic(self.settings["youtube"]["headers"], self.settings["youtube"]["user_id"])

return self.api.create_playlist(name, info, privacy, video_ids=tracks)

def rate_song(self, id, rating):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def test_setup(self):
tmp_path = DEFAULT_PATH.with_suffix(".tmp")
with (
mock.patch("sys.argv", ["", "setup"]),
mock.patch("builtins.input", side_effect=["3", "a", "b", "yes", ""]),
mock.patch("builtins.input", side_effect=["4", "a", "b", "yes", ""]),
mock.patch(
"ytmusicapi.auth.oauth.credentials.OAuthCredentials.token_from_code",
return_value=json.loads(Settings()["youtube"]["headers"]),
Expand Down

0 comments on commit 04d0084

Please sign in to comment.