Skip to content

Commit

Permalink
Merge pull request #4 from chekos/auth
Browse files Browse the repository at this point in the history
Auth
  • Loading branch information
chekos committed Oct 8, 2022
2 parents b74c322 + 9e54d64 commit e63b297
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 22 deletions.
1 change: 0 additions & 1 deletion .github/workflows/force-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v3
- name: Set up Python
Expand Down
23 changes: 21 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
cache: pip
cache-dependency-path: '**/setup.py'
- name: Cache playwright
id: cache-playwright
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright/
Expand All @@ -27,14 +28,32 @@ jobs:
uses: actions/cache@v3
with:
path: ~/.config/esporifai
key: ${{ runner.os }}-spotify
key: ${{ runner.os }}-spotify-v2
- name: Install dependencies
if: hashFiles('setup.py')
run: |
pip install -e '.[test]'
- name: Install Chromium
if: steps.cache-playwright.outputs.cache-hit != 'true'
run: |
playwright install chromium
- name: Auth check
run: |
if [ esporifai auth --check ]
then
echo "Credentials already present."
else
echo "Authorizing"
esporifai auth --force
fi
env:
SPOTIFY_CLIENT_ID: ${{ secrets.SPOTIFY_CLIENT_ID }}
SPOTIFY_AUTH_STRING: ${{ secrets.SPOTIFY_AUTH_STRING }}
USERNAME: ${{ secrets.USERNAME }}
PASSWORD: ${{ secrets.PASSWORD }}
REDIRECT_URI: ${{ secrets.REDIRECT_URI }}
- name: Run tests
run: |
esporifai get-top artists --limit 1 --trim --output - | jq '.[0].name'
pytest
env:
SPOTIFY_CLIENT_ID: ${{ secrets.SPOTIFY_CLIENT_ID }}
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
cache: pip
cache-dependency-path: '**/setup.py'
- name: Cache playwright
id: cache-playwright
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright/
Expand All @@ -33,10 +34,19 @@ jobs:
if: hashFiles('setup.py')
run: |
pip install -e '.[test]'
- name: Install Chromium
if: steps.cache-playwright.outputs.cache-hit != 'true'
run: |
playwright install chromium
- name: Top Artist
- name: Auth check
run: |
esporifai get-top artists --limit 1 --trim --output - | jq '.[0].name'
if [ esporifai auth --check ]
then
echo "Credentials already present."
else
echo "Authorizing"
esporifai auth --force
fi
env:
SPOTIFY_CLIENT_ID: ${{ secrets.SPOTIFY_CLIENT_ID }}
SPOTIFY_AUTH_STRING: ${{ secrets.SPOTIFY_AUTH_STRING }}
Expand Down
6 changes: 5 additions & 1 deletion esporifai/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def get_track(

return response


def get_several_tracks(
access_token: str,
track_ids: list,
Expand All @@ -44,6 +45,7 @@ def get_several_tracks(

return response


def get_artist(
access_token: str,
artist_id: str,
Expand All @@ -64,6 +66,7 @@ def get_artist(

return response


def get_several_artists(
access_token: str,
artist_ids: list,
Expand All @@ -85,6 +88,7 @@ def get_several_artists(

return response


def get_track_audio_analysis(
access_token: str,
track_id: str,
Expand Down Expand Up @@ -174,4 +178,4 @@ def get_user_recently_played(

response = httpx.get(url=url, params=params, headers=headers)

return response
return response
17 changes: 16 additions & 1 deletion esporifai/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
__version__,
__app_name__,
)
from .utils import handle_authorization, handle_response, handle_data
from .utils import auth_check, handle_authorization, handle_response, handle_data


def init():
Expand All @@ -37,6 +37,21 @@ def init():
cli = typer.Typer(callback=init)


@cli.command()
def auth(
force: bool = typer.Option(False, "--force", help="Force authorization flow"),
check: bool = typer.Option(
False, "--check", help="Check if auth credentials are saved."
),
):
if check:
print(auth_check())
return None

global token_info
token_info = handle_authorization(save_files=True, force=force)


@cli.command()
def get_top(
item_type: GetTopItems = typer.Argument(
Expand Down
4 changes: 4 additions & 0 deletions esporifai/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import urllib.parse
from enum import Enum
from pathlib import Path
from hashlib import blake2b

from dotenv import dotenv_values
from typer import get_app_dir
Expand All @@ -27,6 +28,9 @@
REDIRECT_URI = config["REDIRECT_URI"]
USERNAME = config["USERNAME"]
PASSWORD = config["PASSWORD"]
ESPORIFAI_ID = blake2b(
f"{USERNAME}:{PASSWORD}".encode("utf-8"), digest_size=13
).hexdigest()
SCOPE = "user-read-recently-played user-top-read user-library-read playlist-read-collaborative playlist-read-private user-follow-read"
SPOTIFY_AUTH_URL = "https://accounts.spotify.com/authorize"
SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"
Expand Down
51 changes: 36 additions & 15 deletions esporifai/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,24 @@
USERNAME,
__app_name__,
__version__,
ESPORIFAI_ID,
)


def auth_check(user_id: str = ESPORIFAI_ID):
with open(AUTH_FILE, "r") as auth_file:
auth_file = json.load(auth_file)
return bool(auth_file.get(user_id))


def is_expired(expires_at):
now = dt.now()
return now > dt.fromisoformat(expires_at)


def retrieve_code(write: bool = False):
with sync_playwright() as p:
browser = p.chromium.launch(slow_mo=100)
browser = p.chromium.launch(slow_mo=300)
context = browser.new_context()
page = context.new_page()
page.goto(AUTH_CODE_URL)
Expand All @@ -45,16 +52,16 @@ def retrieve_code(write: bool = False):
page.wait_for_url(f"{REDIRECT_URI}**", timeout=90_000)

# Authorized page
auth = {}
auth["code"] = page.url.split("code=")[-1]
auth["scope"] = SCOPE
auth = {ESPORIFAI_ID: {}}
auth[ESPORIFAI_ID]["code"] = page.url.split("code=")[-1]
auth[ESPORIFAI_ID]["scope"] = SCOPE

if write:

with open(AUTH_FILE, "w") as auth_file:
json.dump(auth, auth_file)

return auth
return auth[ESPORIFAI_ID]


def request_token(
Expand All @@ -77,9 +84,11 @@ def request_token(
seconds=int(response_data["expires_in"])
)

token_data = {ESPORIFAI_ID: response_data}

if write:
with open(TOKEN_FILE, "w") as token_file:
json.dump(response_data, token_file, default=str)
json.dump(token_data, token_file, default=str)

return response_data

Expand All @@ -104,9 +113,11 @@ def refresh_token(
)
response_data["refresh_token"] = refresh_token

token_data = {ESPORIFAI_ID: response_data}

if write:
with open(TOKEN_FILE, "w") as token_file:
json.dump(response_data, token_file, default=str)
json.dump(token_data, token_file, default=str)

return response_data

Expand All @@ -119,20 +130,30 @@ def handle_authorization(save_files: bool = False, force: bool = False):

if AUTH_FILE.exists():
with open(AUTH_FILE, "r") as auth_file:
auth = json.load(auth_file)

if auth["scope"] != SCOPE:
# need new code
auth_file = json.load(auth_file)

if ESPORIFAI_ID in auth_file.keys():
auth = auth_file[ESPORIFAI_ID]
if auth["scope"] != SCOPE:
# need new code
auth = retrieve_code(write=save_files)
else:
auth = retrieve_code(write=save_files)
else:
auth = retrieve_code(write=save_files)

if TOKEN_FILE.exists():
with open(TOKEN_FILE, "r") as token_file:
token_info = json.load(token_file)

if is_expired(token_info["expires_at"]):
token_info = refresh_token(token_info["refresh_token"], write=save_files)
token_info_file = json.load(token_file)

if ESPORIFAI_ID in token_info_file.keys():
token_info = token_info_file[ESPORIFAI_ID]
if is_expired(token_info["expires_at"]):
token_info = refresh_token(
token_info["refresh_token"], write=save_files
)
else:
token_info = request_token(auth["code"], write=save_files)
else:
token_info = request_token(auth["code"], write=save_files)

Expand Down

0 comments on commit e63b297

Please sign in to comment.