From 8a591f173cfccf072c31af88656a5ed12936fcfe Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Apr 2020 14:19:57 +0200 Subject: Initial commit --- README.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++ pyfunkwhale/__init__.py | 0 pyfunkwhale/client.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ pyfunkwhale/funkwhale.py | 17 +++++++++++ pyfunkwhale/utils.py | 18 ++++++++++++ 5 files changed, 184 insertions(+) create mode 100644 README.md create mode 100644 pyfunkwhale/__init__.py create mode 100644 pyfunkwhale/client.py create mode 100644 pyfunkwhale/funkwhale.py create mode 100644 pyfunkwhale/utils.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..f108fa6 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# PyFunkwhale + +A simple funkwhale API client library + +Since API is not frozen, this client library is written for the version +`0.20.1`. + +# Install + +Only for dev for the momement: + +``` +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +# Use + +This client library use th OAuth2 Authorization Code flow and ask to the user +to authorize this app. I'm not ok with how I do this for the moment. If you +have suggestion about how to do this, I will gladly accept to discuse it. +And you can also send me suggestions for other parts of this module ;) + +Example usage: + +``` +#!/usr/bin/env python +# -*- condig: utf-8 -*- + +import requests + +from pyfunkwhale.funkwhale import Funkwhale + +client_name = "pyfunkwhale" + +redirect_uri = "urn:ietf:wg:oauth:2.0:oob" + +# Obviously dont copy past and check the doc for how to get it: +# https://docs.funkwhale.audio/developers/authentication.html#create-an-app +client_id = "IFQuq6iB7Ta5LVxCUV8ibo65x588bgtI4rsa46cgm" +client_secret = "RMurKpQsoaZKbVpbse5o2wrJ5E4dMbvDs54JMsK5fDY5AK2QP8tJxoN7ApjryoCdWBUk02dExNTxzgUOZHFmSRcYdbJXbkLghXn6mvQMs9J8uIMpFIrehBp" + +# This is your instance and login information +# This example is based on https://docs.funkwhale.audio/swagger/ +username = "demo" +password = "demo" +domain = "https://demo.funkwhale.audio" + +scopes = "read" + +authorization_endpoint = "https://demo.funkwhale.audio/authorize" +token_endpoint = "https://demo.funkwhale.audio/api/v1/oauth/token/" + + +# Save the OAuth2 infos in file, this is ugly yup +token_filename = 'oauth_token.data' + +funkwhale = Funkwhale(client_name, redirect_uri, client_id, client_secret, + scopes, username, password, domain, authorization_endpoint, + token_endpoint, token_filename) + +artists = funkwhale.artists() + +print(artists) +``` + +# Features + +List of features implemented or planned: + +[x] Login with OAuth2 Authorization Code flow +[x] List artists diff --git a/pyfunkwhale/__init__.py b/pyfunkwhale/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyfunkwhale/client.py b/pyfunkwhale/client.py new file mode 100644 index 0000000..fb89b54 --- /dev/null +++ b/pyfunkwhale/client.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- conding: utf-8 -*- + +import json +from time import time +from requests_oauthlib import OAuth2Session + +from pyfunkwhale.utils import read_file, write_file + + +class Client(object): + + def __init__(self, client_name, redirect_uri, client_id, + client_secret, scopes, username, password, domain, + authorization_endpoint, token_endpoint, + token_filename): + self.client_name = client_name + self.redirect_uri = redirect_uri + self.client_id = client_id + self.client_secret = client_secret + self.scopes = scopes + self.token = None + + self.username = username + self.password = password + self.domain = domain + + self.authorization_endpoint = authorization_endpoint + self.token_endpoint = token_endpoint + self.token_filename = token_filename + self.oauth_client = OAuth2Session( + self.client_id, + redirect_uri=self.redirect_uri, + scope=self.scopes) + self.authorization_url, self.state = self.oauth_client. \ + authorization_url( + self.authorization_endpoint) + + try: + self.token = json.loads(read_file(token_filename)) + self._refresh_token() + except FileNotFoundError: + self._get_token() + write_file(token_filename, self.token) + + def _get_token(self): + print("For authorizate this app go to:\n{}".format( + self.authorization_url)) + self.authorization_code = input("Enter response code: ") + + self.token = self.oauth_client.fetch_token( + self.token_endpoint, + code=self.authorization_code, + client_secret=self.client_secret) + + def _refresh_token(self): + if time() - 60 > self.token["expires_at"]: + self.token = self.oauth_client.refresh_token( + self.token_endpoint, + refresh_token=self.token["refresh_token"], + client_id=self.client_id, + client_secret=self.client_secret) + write_file(self.token_filename, self.token) + + def call(self, endpoint, method): + self._refresh_token() + headers = {'Authorization': self.token['token_type'] + ' ' + + self.token['access_token']} + + call = getattr(self.oauth_client, method) + + r = call( + self.domain + '/api/v1/' + endpoint, + headers=headers) + + return r diff --git a/pyfunkwhale/funkwhale.py b/pyfunkwhale/funkwhale.py new file mode 100644 index 0000000..8f399ab --- /dev/null +++ b/pyfunkwhale/funkwhale.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +from pyfunkwhale.client import Client + + +class Funkwhale(object): + + def __init__(self, client_name, redirect_uri, client_id, + client_secret, scopes, username, password, domain, + authorization_endpoint, token_endpoint, token_filename): + self.client = Client( + client_name, redirect_uri, client_id, client_secret, + scopes, username, password, domain, authorization_endpoint, + token_endpoint, token_filename) + + def artists(self): + return self.client.call('/artists/', 'get').json() diff --git a/pyfunkwhale/utils.py b/pyfunkwhale/utils.py new file mode 100644 index 0000000..9ba5d0f --- /dev/null +++ b/pyfunkwhale/utils.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json + + +def read_file(filename): + with open(filename, 'r') as file: + data = file.read() + + return data + + +def write_file(filename, data): + with open(filename, 'w') as file: + file.write(json.dumps(data)) + + return data -- cgit v1.2.1