aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneodarz <neodarz@neodarz.net>2020-04-11 14:19:57 +0200
committerneodarz <neodarz@neodarz.net>2020-04-11 14:19:57 +0200
commit8a591f173cfccf072c31af88656a5ed12936fcfe (patch)
tree08f0f2ae762a711a94cd34a70e8684d7f6853e7b
downloadpyfunkwhale-8a591f173cfccf072c31af88656a5ed12936fcfe.tar.xz
pyfunkwhale-8a591f173cfccf072c31af88656a5ed12936fcfe.zip
Initial commit
-rw-r--r--README.md73
-rw-r--r--pyfunkwhale/__init__.py0
-rw-r--r--pyfunkwhale/client.py76
-rw-r--r--pyfunkwhale/funkwhale.py17
-rw-r--r--pyfunkwhale/utils.py18
5 files changed, 184 insertions, 0 deletions
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
--- /dev/null
+++ b/pyfunkwhale/__init__.py
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