From 7f1a6a6e2527ba15d356d1961c1c9afd448b9c2e Mon Sep 17 00:00:00 2001 From: Xevion Date: Sat, 21 Dec 2019 14:12:17 -0600 Subject: [PATCH] changed error page, MASSIVE new sound extension added with working YouTube duration, preparation and streaming API steps, wsgi random comment removal --- .gitignore | 1 + app/__init__.py | 2 +- app/simple_routes.py | 2 +- app/sound.py | 90 ++++++++++++++++++++++++++ app/templates/{404.html => error.html} | 6 +- requirements.txt | 28 ++++---- wsgi.py | 2 - 7 files changed, 110 insertions(+), 21 deletions(-) create mode 100644 app/sound.py rename app/templates/{404.html => error.html} (53%) diff --git a/.gitignore b/.gitignore index f211797..57969ae 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ app/static/token.dat keys.json .cache-xevioni auth.json +app/sounds/* \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 5dc6a1e..7dcd06e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -17,6 +17,6 @@ migrate = Migrate(app, db) from app import models from app import routes, simple_routes, hidden, dashboard -from app import ftbhot, custom, spotify, panzer +from app import ftbhot, custom, spotify, panzer, sound app.jinja_env.globals.update(get_hidden=routes.get_hidden) \ No newline at end of file diff --git a/app/simple_routes.py b/app/simple_routes.py index 96e00fb..7634e4b 100644 --- a/app/simple_routes.py +++ b/app/simple_routes.py @@ -24,4 +24,4 @@ def unauthorized(e): @app.errorhandler(404) def page_not_found(e): # note that we set the 404 status explicitly - return render_template('404.html'), 404 \ No newline at end of file + return render_template('error.html', code=404, message='Content not found...'), 404 \ No newline at end of file diff --git a/app/sound.py b/app/sound.py new file mode 100644 index 0000000..47de89c --- /dev/null +++ b/app/sound.py @@ -0,0 +1,90 @@ +from app import app +from flask import send_file, redirect, url_for, render_template +from mutagen.mp3 import MP3 +import os +import re +import json +import subprocess + +# Services => Expected Data +# YouTube => Video ID +# Soundcloud => + +# Filenaming/API Convention Examples +# Original URL/URI => API Path => Connected File +# https://www.youtube.com/watch?v=awtYiVGXiaY => /stream/youtube/awtYiVGXiaY => youtube/awtYiVGXiaY.mp3 +# https://soundcloud.com/yungraredeath/fall-in-line-w-kxng-prod-mars-mission => /stream/soundcloud/fall-in-line-w-kxng-prod-mars-mission---yungraredeath => soundcloud/fall-in-line-w-kxng-prod-mars-mission---yungraredeath.mp3 +# spotify:track:16PmczUxlX7dpr6ror6pXd => /duration/spotify/16PmczUxlX7dpr6ror6pXd => spotify/16PmczUxlX7dpr6ror6pXd.mp3 + +class YouTubeHandler: + @staticmethod + def url(videoid): + return f'https://www.youtube.com/watch?v={videoid}' + + @staticmethod + def getConfig(videoid): + with open(os.path.join('app', 'sounds', 'filenames.json'), 'r') as file: + return json.load(file)['youtube'][videoid] + + @staticmethod + def filename(videoid): + try: + config = YouTubeHandler.getConfig(videoid) + return config['filename'] + except KeyError: + filename = subprocess.run( + ['youtube-dl', '-x', '--audio-format', 'mp3', '--restrict-filenames', '--get-filename', + YouTubeHandler.url(videoid)], encoding='utf-8', capture_output=True).stdout + filename = filename.split('.') + filename[-1] = 'mp3' + return '.'.join(filename) + + @staticmethod + def path(videoid): + try: + config = YouTubeHandler.getConfig(videoid) + return config['path'] + except KeyError: + filename = YouTubeHandler.filename(videoid) + path = os.path.join('app', 'sounds', 'youtube', filename) + with open(os.path.join('app', 'sounds', 'filenames.json'), 'r+') as file: + config = json.load(file) + config['youtube'][videoid] = { + "filename" : filename, + "path" : path + } + file.seek(0) + file.write(json.dumps(config)) + file.truncate() + return path + + @staticmethod + def download(videoid): + config = YouTubeHandler.getConfig(videoid) + if not os.path.exists(config['path']): + subprocess.run(['youtube-dl', '-x', '--restrict-filenames', '--audio-format', 'mp3', YouTubeHandler.url(videoid)]) + print(os.listdir('.')) + os.rename(config['filename'], config['path']) + +service_functions = { + 'youtube' : YouTubeHandler, + 'spotify' : {'url' : None, 'path' : None}, + 'soundcloud' : {'url' : None, 'path' : None} +} + +# Streams a prepared MP3 back to the client +@app.route('/stream//') +def stream(service, mediaid): + prepare(service, mediaid) + if service == 'youtube': + config = YouTubeHandler.getConfig(mediaid) + return send_file(os.path.join(os.path.dirname(__file__), '..', config['path']), attachment_filename=config['filename']) + return '???' + +# Prepares a URL for download, returning the duration it should play for if streamed +@app.route('/prepare//') +def prepare(service, mediaid): + filepath = service_functions[service].path(mediaid) + service_functions[service].download(mediaid) + print(filepath) + return str(MP3(filepath).info.length) \ No newline at end of file diff --git a/app/templates/404.html b/app/templates/error.html similarity index 53% rename from app/templates/404.html rename to app/templates/error.html index f643f95..72aff54 100644 --- a/app/templates/404.html +++ b/app/templates/error.html @@ -5,10 +5,10 @@

- {{ code }} + {{ code if code is not none else 'Error' }}

-

- {{ message }} Go home? +

+ {{ message if message is not none else 'Error encountered' }} {{ url_message if url_message is not none else 'Go home?' }}

diff --git a/requirements.txt b/requirements.txt index 37d41c2..587c36b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,21 @@ -Flask_Migrate==2.5.2 -pyperclip==1.7.0 -spotipy==2.4.4 -alembic==1.2.1 -matplotlib==3.1.1 -SQLAlchemy==1.3.10 hurry.filesize==0.9 -Faker==2.0.3 -xmltodict==0.12.0 -numpy==1.17.3 -Flask_SQLAlchemy==2.4.1 +Flask_Migrate==2.5.2 +Flask==1.1.1 +alembic==1.2.1 +SQLAlchemy==1.3.10 +pyperclip==1.7.0 +Werkzeug==0.16.0 requests==2.20.0 WTForms==2.2.1 -Flask_WTF==0.14.2 -Werkzeug==0.16.0 -Flask==1.1.1 -Flask_Login==0.4.1 +xmltodict==0.12.0 +spotipy==2.4.4 mistune==0.8.4 +Flask_Login==0.4.1 +Flask_WTF==0.14.2 +matplotlib==3.1.1 +Faker==2.0.3 +numpy==1.17.3 +Flask_SQLAlchemy==2.4.1 Pillow==6.2.1 python_dateutil==2.8.1 hurry==1.1 diff --git a/wsgi.py b/wsgi.py index 2957335..c7e429b 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,8 +1,6 @@ from app import app, db from app.models import User, Post, Search -# test message - @app.shell_context_processor def make_shell_context(): return {'db' : db, 'User' : User, 'Post' : Post, 'Search' : Search}