mirror of
https://github.com/Xevion/v1.xevion.dev.git
synced 2025-12-11 00:09:05 -06:00
changed error page, MASSIVE new sound extension added with working YouTube duration, preparation and streaming API steps, wsgi random comment removal
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@ app/static/token.dat
|
|||||||
keys.json
|
keys.json
|
||||||
.cache-xevioni
|
.cache-xevioni
|
||||||
auth.json
|
auth.json
|
||||||
|
app/sounds/*
|
||||||
@@ -17,6 +17,6 @@ migrate = Migrate(app, db)
|
|||||||
|
|
||||||
from app import models
|
from app import models
|
||||||
from app import routes, simple_routes, hidden, dashboard
|
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)
|
app.jinja_env.globals.update(get_hidden=routes.get_hidden)
|
||||||
@@ -24,4 +24,4 @@ def unauthorized(e):
|
|||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
# note that we set the 404 status explicitly
|
# note that we set the 404 status explicitly
|
||||||
return render_template('404.html'), 404
|
return render_template('error.html', code=404, message='Content not found...'), 404
|
||||||
90
app/sound.py
Normal file
90
app/sound.py
Normal file
@@ -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/<service>/<mediaid>')
|
||||||
|
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/<service>/<mediaid>')
|
||||||
|
def prepare(service, mediaid):
|
||||||
|
filepath = service_functions[service].path(mediaid)
|
||||||
|
service_functions[service].download(mediaid)
|
||||||
|
print(filepath)
|
||||||
|
return str(MP3(filepath).info.length)
|
||||||
@@ -5,10 +5,10 @@
|
|||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container has-text-centered">
|
<div class="container has-text-centered">
|
||||||
<p class="title">
|
<p class="title">
|
||||||
{{ code }}
|
{{ code if code is not none else 'Error' }}
|
||||||
</p>
|
</p>
|
||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
{{ message }} <em href="{{ url_for('index') }}">Go home?</em>
|
{{ message if message is not none else 'Error encountered' }} <em href="{{ url if url is not none else url_for('index') }}">{{ url_message if url_message is not none else 'Go home?' }}</em>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -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
|
hurry.filesize==0.9
|
||||||
Faker==2.0.3
|
Flask_Migrate==2.5.2
|
||||||
xmltodict==0.12.0
|
Flask==1.1.1
|
||||||
numpy==1.17.3
|
alembic==1.2.1
|
||||||
Flask_SQLAlchemy==2.4.1
|
SQLAlchemy==1.3.10
|
||||||
|
pyperclip==1.7.0
|
||||||
|
Werkzeug==0.16.0
|
||||||
requests==2.20.0
|
requests==2.20.0
|
||||||
WTForms==2.2.1
|
WTForms==2.2.1
|
||||||
Flask_WTF==0.14.2
|
xmltodict==0.12.0
|
||||||
Werkzeug==0.16.0
|
spotipy==2.4.4
|
||||||
Flask==1.1.1
|
|
||||||
Flask_Login==0.4.1
|
|
||||||
mistune==0.8.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
|
Pillow==6.2.1
|
||||||
python_dateutil==2.8.1
|
python_dateutil==2.8.1
|
||||||
hurry==1.1
|
hurry==1.1
|
||||||
|
|||||||
2
wsgi.py
2
wsgi.py
@@ -1,8 +1,6 @@
|
|||||||
from app import app, db
|
from app import app, db
|
||||||
from app.models import User, Post, Search
|
from app.models import User, Post, Search
|
||||||
|
|
||||||
# test message
|
|
||||||
|
|
||||||
@app.shell_context_processor
|
@app.shell_context_processor
|
||||||
def make_shell_context():
|
def make_shell_context():
|
||||||
return {'db' : db, 'User' : User, 'Post' : Post, 'Search' : Search}
|
return {'db' : db, 'User' : User, 'Post' : Post, 'Search' : Search}
|
||||||
|
|||||||
Reference in New Issue
Block a user