tamland / python-tidal

Python API for TIDAL music streaming service
GNU Lesser General Public License v3.0
406 stars 110 forks source link

Add Oauth login from file helper functions #138

Closed tehkillerbee closed 8 months ago

tehkillerbee commented 1 year ago
PretzelVector commented 1 year ago
import tidalapi
import os

class Session(tidalapi.Session):
    def __init__(self):
        super().__init__()

    def easy_login(self):
        if not os.path.exists("token.txt"):
            self.login_oauth_simple()

            with open("token.txt", "w") as f:
                f.write(
                    f"{self.token_type}\n{self.access_token}\n{self.refresh_token}\n{self.expiry_time}"
                )
        else:
            with open("token.txt", "r") as f:
                token_type = f.readline().strip()
                access_token = f.readline().strip()
                refresh_token = f.readline().strip()
                expiry_time = f.readline().strip()

            self.load_oauth_session(
                token_type, access_token, refresh_token, expiry_time
            )

if __name__ == "__main__":
    session = Session()
    session.easy_login()
tehkillerbee commented 1 year ago

Hello and thanks for the quick example!

I know this is strictly not a PR yet, but my only suggestion would be to use json, similar to what we do here: https://github.com/tehkillerbee/mopidy-tidal/blob/master/mopidy_tidal/backend.py#L53-L66

https://github.com/tehkillerbee/mopidy-tidal/blob/master/mopidy_tidal/backend.py#L128-L140

2e0byo commented 1 year ago

There's also an example now in the tests, albeit not yet signposted. See https://github.com/tamland/python-tidal/blob/master/tests/conftest.py#L80-L97.

The only difference is we just dump the token dict straight to disk. I'm not quite sure @tehkillerbee why we don't in mopidy-tidal, although we shouldn't change it now.

tehkillerbee commented 1 year ago

@2e0byo I used JSON to store the four fields required to load the session. But you suggest storing the whole session dict instead?

This is how I currently do it in various python scripts that uses tidalapi:


import logging
import json
from pathlib import Path
#import sys
#sys.path.append('./python-tidal')
import tidalapi

logger = logging.getLogger(__name__)

oauth_file = Path("tidal-oauth.json")

class TestTidalapi:
    def __init__(self):
        self._active_session = tidalapi.Session()

    def _save_oauth_session(self, oauth_file: Path):
        # create a new session
        if self._active_session.check_login():
            # store current OAuth session
            data = {}
            data["token_type"] = {"data": self._active_session.token_type}
            data["session_id"] = {"data": self._active_session.session_id}
            data["access_token"] = {"data": self._active_session.access_token}
            data["refresh_token"] = {"data": self._active_session.refresh_token}
            with oauth_file.open("w") as outfile:
                json.dump(data, outfile)
            self._oauth_saved = True

    def _load_oauth_session(self, **data):
        assert self._active_session, "No session loaded"
        args = {
            "token_type": data.get("token_type", {}).get("data"),
            "access_token": data.get("access_token", {}).get("data"),
            "refresh_token": data.get("refresh_token", {}).get("data"),
        }

        self._active_session.load_oauth_session(**args)

    def _login(self):
        try:
            # attempt to reload existing session from file
            with open(oauth_file) as f:
                logger.info("Loading OAuth session from %s...", oauth_file)
                data = json.load(f)
                self._load_oauth_session(**data)
        except Exception as e:
            logger.info("Could not load OAuth session from %s: %s", oauth_file, e)

        if not self._active_session.check_login():
            logger.info("Creating new OAuth session...")
            self._active_session.login_oauth_simple()
            self._save_oauth_session(oauth_file)

        if self._active_session.check_login():
            logger.info("TIDAL Login OK")
        else:
            logger.info("TIDAL Login KO")
            raise ConnectionError("Failed to log in.")

    def run(self):
        # do login
        self._login()

        # Will run until you visit the printed url and link your account
        album = self._active_session.album(103386847)
        print(album.name)
        tracks = album.tracks()
        for track in tracks:
            print(track.name)
            print(track.version)
            for artist in track.artists:
                print(' by: ', artist.name)

if __name__ == "__main__":
    TestTidalapi().run()