Skip to content

Commit

Permalink
Version 0.5.0 - Finishes remote API Keys
Browse files Browse the repository at this point in the history
  • Loading branch information
cfangmeier committed May 23, 2019
1 parent 74eff44 commit 80233e1
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 50 deletions.
16 changes: 14 additions & 2 deletions README.md
Expand Up @@ -74,9 +74,21 @@ The player supports Last.fm scrobbling. To enable it, you need to run:
tuijam get_lastfm_token
```

# Queue and History
# API Key Management

The file format for the queue and history persistence features is in flux. Therefore, upgrading could result in losing the current queue and play history. This should stabilize in the near future.
Youtube and Last.fm integration uses api keys that are supplied by me. TUIJam queries them at runtime from a server that I maintain. If the server goes down, of if you would just prefer not to rely on it, you can specify your own keys in the config file. Keys are only queried if they are not present in the config file.

```yaml
GOOGLE_DEVELOPER_KEY: "yourdeveloperkeyhere"
LASTFM_API_KEY: "yourapikeyhere"
LASTFM_API_SECRET: "yoursecrethere"
```

You can also run your own server using or adapting `key_server_example.py` and setting your config file to point to your server.

```yaml
key_server: "https://my-tuijam-key-server.io"
```

# Controls
- `ctrl-c` quit
Expand Down
8 changes: 4 additions & 4 deletions requirements.txt
@@ -1,10 +1,10 @@
rsa>=4.0
requests>=2.21.0
gmusicapi==11.0.0
urwid==2.0.1
gmusicapi>=11.0.0
urwid>=2.0.1
pyYAML>=4.2b1
python-mpv==0.3.6
python-mpv>=0.3.6
scrypt>=0.8.0
PyGObject>=3.28.3
pydbus==0.6.0
pydbus>=0.6.0
google-api-python-client>=1.7.4
44 changes: 21 additions & 23 deletions setup.py
Expand Up @@ -4,40 +4,38 @@
import sys

if sys.version_info < (3, 6):
print('tuijam requires python>=3.6.')
print("tuijam requires python>=3.6.")
exit(1)

with open('requirements.txt') as f:
with open("requirements.txt") as f:
requirements = f.readlines()

with open('README.md') as f:
with open("README.md") as f:
desc = f.read()

setup(
name='tuijam',
name="tuijam",
version=__version__,
description='A fancy TUI client for Google Play Music',
description="A fancy TUI client for Google Play Music",
long_description=desc,
long_description_content_type='text/markdown',
url='https://github.com/cfangmeier/tuijam',
author='Caleb Fangmeier',
author_email='caleb@fangmeier.tech',
license='MIT',
long_description_content_type="text/markdown",
url="https://github.com/cfangmeier/tuijam",
author="Caleb Fangmeier",
author_email="caleb@fangmeier.tech",
license="MIT",
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: MIT License',
'Environment :: Console :: Curses',
'Intended Audience :: Developers',
'Intended Audience :: End Users/Desktop',
'Operating System :: Unix',
'Topic :: Multimedia :: Sound/Audio :: Players',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3 :: Only',
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
"Environment :: Console :: Curses",
"Intended Audience :: Developers",
"Intended Audience :: End Users/Desktop",
"Operating System :: Unix",
"Topic :: Multimedia :: Sound/Audio :: Players",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3 :: Only",
],
keywords='terminal music streaming',
keywords="terminal music streaming",
install_requires=requirements,
packages=find_packages(),
entry_points={
'console_scripts': ['tuijam=tuijam.app:main'],
},
entry_points={"console_scripts": ["tuijam=tuijam.app:main"]},
)
6 changes: 5 additions & 1 deletion tuijam/__init__.py
@@ -1,4 +1,8 @@
from os.path import join, expanduser

__version__ = "0.4.1"
__version__ = "0.5.0"
CONFIG_DIR = join(expanduser("~"), ".config", "tuijam")
CONFIG_FILE = join(CONFIG_DIR, "config.yaml")
LOG_FILE = join(CONFIG_DIR, "log.txt")
HISTORY_FILE = join(CONFIG_DIR, "hist.json")
QUEUE_FILE = join(CONFIG_DIR, "queue.json")
19 changes: 8 additions & 11 deletions tuijam/app.py
Expand Up @@ -22,7 +22,7 @@
)
from .music_objects import serialize, deserialize
from .ui import SearchInput, SearchPanel, QueuePanel, PlayBar
from tuijam import CONFIG_DIR
from tuijam import CONFIG_DIR, CONFIG_FILE, QUEUE_FILE, HISTORY_FILE
from tuijam.utility import lookup_keys


Expand Down Expand Up @@ -121,14 +121,13 @@ def login(self):
return self.g_api.login(*credentials)

def read_config(self):
config_file = join(CONFIG_DIR, "config.yaml")

if not isfile(config_file):
if not isfile(CONFIG_FILE):
if not self.first_time_setup():
return

email, password, device_id = None, None, None
with open(config_file) as f:
with open(CONFIG_FILE) as f:
config = yaml.safe_load(f.read())

if config.get("encrypted", False):
Expand Down Expand Up @@ -226,9 +225,7 @@ def write_config(email, password, device_id, config_pw):
data["reverse_scrolling"] = False
data["video"] = False

config_file = join(CONFIG_DIR, "config.yaml")

with open(config_file, "w") as outfile:
with open(CONFIG_FILE, "w") as outfile:
yaml.safe_dump(data, outfile, default_flow_style=False)

def get_device_id(self, email, password):
Expand Down Expand Up @@ -607,12 +604,12 @@ def save_queue(self):

queue.extend(self.queue_panel.queue)

with open(join(CONFIG_DIR, "queue.json"), "w") as f:
with open(QUEUE_FILE, "w") as f:
f.write(serialize(queue))

def restore_queue(self):
try:
with open(join(CONFIG_DIR, "queue.json"), "r") as f:
with open(QUEUE_FILE, "r") as f:
self.queue_panel.add_songs_to_queue(deserialize(f.read()))

except (AttributeError, FileNotFoundError) as e:
Expand All @@ -621,12 +618,12 @@ def restore_queue(self):
self.queue_panel.clear()

def save_history(self):
with open(join(CONFIG_DIR, "hist.json"), "w") as f:
with open(HISTORY_FILE, "w") as f:
f.write(serialize(self.history))

def restore_history(self):
try:
with open(join(CONFIG_DIR, "hist.json"), "r") as f:
with open(HISTORY_FILE, "r") as f:
self.history = deserialize(f.read())
except (AttributeError, FileNotFoundError) as e:
logging.exception(e)
Expand Down
46 changes: 37 additions & 9 deletions tuijam/utility.py
Expand Up @@ -4,19 +4,47 @@ def sec_to_min_sec(sec_tot):


def lookup_keys(*key_ids):
import rsa
import base64
import yaml
import rsa
import requests

(pub, priv) = rsa.newkeys(512)
from tuijam import CONFIG_FILE

keys = [None] * len(key_ids)
# First, check if any are in configuration file
with open(CONFIG_FILE, "r") as f:
cfg = yaml.safe_load(f)
for idx, id_ in enumerate(key_ids):
try:
keys[idx] = cfg[id_]
except KeyError:
pass

# Next, if any unspecified in config file, ask the server for them
to_query = {}
for idx, (id_, key) in enumerate(zip(key_ids, keys)):
if key is None:
# keep track of position of each key so output order matches
to_query[id_] = idx

print(to_query)
if to_query:
(pub, priv) = rsa.newkeys(512) # Generate new RSA key pair. Do not reuse keys!
host = cfg.get("key_server", "https://tuijam.fangmeier.tech")

host = "https://tuijam.fangmeier.tech"
res = requests.post(
host, json={"public_key": pub.save_pkcs1().decode(), "ids": list(to_query)}
)

res = requests.post(
host, json={"public_key": pub.save_pkcs1().decode(), "ids": key_ids}
)
for id_, key_encrypted in res.json().items():
# On the server, the api key is encrypted with the public RSA key,
# and then base64 encoded to be delivered. Reverse that process here.
key_decrypted = rsa.decrypt(
base64.decodebytes(key_encrypted.encode()), priv
).decode()
print(keys)
print(to_query[id_])
keys[to_query[id_]] = key_decrypted

keys = []
for id_, key_enc in res.json().items():
keys.append(rsa.decrypt(base64.decodebytes(key_enc.encode()), priv).decode())
return keys

0 comments on commit 80233e1

Please sign in to comment.