It's been a while
This commit is contained in:
parent
72e121d585
commit
ba1961349c
19 changed files with 117 additions and 66 deletions
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
@ -77,15 +77,15 @@
|
|||
onclick="refresh_channel('{{channel['id']}}', false, function(){location.reload()})">Refresh new videos</button></span>
|
||||
<span><button class="refresh_button"
|
||||
onclick="refresh_channel('{{channel['id']}}', true, function(){location.reload()})">Refresh everything</button></span>
|
||||
<span><a href="/channel/{{channel['id']}}">All</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/pending">Pending</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/ignored">Ignored</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/downloaded">Downloaded</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}{{query_string}}">All</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/pending{{query_string}}">Pending</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/ignored{{query_string}}">Ignored</a></span>
|
||||
<span><a href="/channel/{{channel['id']}}/downloaded{{query_string}}">Downloaded</a></span>
|
||||
{% else %}
|
||||
<span><a href="/videos">All</a></span>
|
||||
<span><a href="/videos/pending">Pending</a></span>
|
||||
<span><a href="/videos/ignored">Ignored</a></span>
|
||||
<span><a href="/videos/downloaded">Downloaded</a></span>
|
||||
<span><a href="/videos{{query_string}}">All</a></span>
|
||||
<span><a href="/videos/pending{{query_string}}">Pending</a></span>
|
||||
<span><a href="/videos/ignored{{query_string}}">Ignored</a></span>
|
||||
<span><a href="/videos/downloaded{{query_string}}">Downloaded</a></span>
|
||||
{% endif %}
|
||||
<span>{{videos|length}} items</span>
|
||||
|
3
frontends/ycdl_flask/ycdl_flask/__init__.py
Normal file
3
frontends/ycdl_flask/ycdl_flask/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from . import ycdl_flask
|
||||
|
||||
site = ycdl_flask.site
|
|
@ -2,22 +2,36 @@
|
|||
Do not execute this file directly.
|
||||
Use ycdl_launch.py to start the server with gevent.
|
||||
'''
|
||||
import logging
|
||||
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)
|
||||
|
||||
import datetime
|
||||
import flask
|
||||
from flask import request
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
import traceback
|
||||
|
||||
import bot
|
||||
import helpers
|
||||
import ycdl
|
||||
import ytapi
|
||||
|
||||
youtube_core = ytapi.Youtube(bot.YOUTUBE_KEY)
|
||||
from voussoirkit import pathclass
|
||||
|
||||
root_dir = pathclass.Path(__file__).parent.parent
|
||||
|
||||
TEMPLATE_DIR = root_dir.with_child('templates')
|
||||
STATIC_DIR = root_dir.with_child('static')
|
||||
FAVICON_PATH = STATIC_DIR.with_child('favicon.png')
|
||||
|
||||
youtube_core = ycdl.ytapi.Youtube(bot.YOUTUBE_KEY)
|
||||
youtube = ycdl.YCDL(youtube_core)
|
||||
|
||||
site = flask.Flask(__name__)
|
||||
site = flask.Flask(
|
||||
__name__,
|
||||
template_folder=TEMPLATE_DIR.absolute_path,
|
||||
static_folder=STATIC_DIR.absolute_path,
|
||||
)
|
||||
site.config.update(
|
||||
SEND_FILE_MAX_AGE_DEFAULT=180,
|
||||
TEMPLATES_AUTO_RELOAD=True,
|
||||
|
@ -91,7 +105,7 @@ def send_file(filepath):
|
|||
if request.method == 'HEAD':
|
||||
outgoing_data = bytes()
|
||||
else:
|
||||
outgoing_data = helpers.read_filebytes(filepath, range_min=range_min, range_max=range_max)
|
||||
outgoing_data = ycdl.helpers.read_filebytes(filepath, range_min=range_min, range_max=range_max)
|
||||
|
||||
response = flask.Response(
|
||||
outgoing_data,
|
||||
|
@ -112,8 +126,8 @@ def root():
|
|||
@site.route('/favicon.ico')
|
||||
@site.route('/favicon.png')
|
||||
def favicon():
|
||||
filename = os.path.join('static', 'favicon.png')
|
||||
return flask.send_file(filename)
|
||||
return flask.send_file(FAVICON_PATH.absolute_path)
|
||||
|
||||
|
||||
@site.route('/channels')
|
||||
def get_channels():
|
||||
|
@ -123,24 +137,30 @@ def get_channels():
|
|||
return flask.render_template('channels.html', channels=channels)
|
||||
|
||||
@site.route('/videos')
|
||||
@site.route('/watch')
|
||||
@site.route('/videos/<download_filter>')
|
||||
@site.route('/channel/<channel_id>')
|
||||
@site.route('/channel/<channel_id>/<download_filter>')
|
||||
def get_channel(channel_id=None, download_filter=None):
|
||||
if channel_id is not None:
|
||||
try:
|
||||
youtube.add_channel(channel_id)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
channel = youtube.get_channel(channel_id)
|
||||
if channel is None:
|
||||
flask.abort(404)
|
||||
else:
|
||||
channel = None
|
||||
|
||||
videos = youtube.get_videos(channel_id=channel_id, download_filter=download_filter)
|
||||
|
||||
search_term = request.args.get('q', None)
|
||||
if search_term is not None:
|
||||
search_term = search_term.lower()
|
||||
videos = [v for v in videos if search_term in v['title'].lower()]
|
||||
search_terms = request.args.get('q', '').lower().strip().replace('+', ' ').split()
|
||||
if search_terms:
|
||||
videos = [v for v in videos if all(term in v['title'].lower() for term in search_terms)]
|
||||
|
||||
video_id = request.args.get('v', '')
|
||||
if video_id:
|
||||
youtube.insert_video(video_id)
|
||||
videos = [youtube.get_video(video_id)]
|
||||
|
||||
limit = request.args.get('limit', None)
|
||||
if limit is not None:
|
||||
|
@ -155,14 +175,12 @@ def get_channel(channel_id=None, download_filter=None):
|
|||
published = datetime.datetime.utcfromtimestamp(published)
|
||||
published = published.strftime('%Y %m %d')
|
||||
video['_published_str'] = published
|
||||
return flask.render_template('channel.html', channel=channel, videos=videos)
|
||||
|
||||
@site.route('/static/<filename>')
|
||||
def get_static(filename):
|
||||
filename = filename.replace('\\', os.sep)
|
||||
filename = filename.replace('/', os.sep)
|
||||
filename = os.path.join('static', filename)
|
||||
return flask.send_file(filename)
|
||||
return flask.render_template(
|
||||
'channel.html',
|
||||
channel=channel,
|
||||
videos=videos,
|
||||
query_string='?' + request.query_string.decode('utf-8'),
|
||||
)
|
||||
|
||||
@site.route('/mark_video_state', methods=['POST'])
|
||||
def post_mark_video_state():
|
||||
|
@ -184,7 +202,7 @@ def post_mark_video_state():
|
|||
@site.route('/refresh_all_channels', methods=['POST'])
|
||||
def post_refresh_all_channels():
|
||||
force = request.form.get('force', False)
|
||||
force = helpers.truthystring(force)
|
||||
force = ycdl.helpers.truthystring(force)
|
||||
youtube.refresh_all_channels(force=force)
|
||||
return make_json_response({})
|
||||
|
||||
|
@ -204,7 +222,7 @@ def post_refresh_channel():
|
|||
flask.abort(404)
|
||||
|
||||
force = request.form.get('force', False)
|
||||
force = helpers.truthystring(force)
|
||||
force = ycdl.helpers.truthystring(force)
|
||||
youtube.refresh_channel(channel_id, force=force)
|
||||
return make_json_response({})
|
||||
|
||||
|
@ -215,7 +233,7 @@ def post_start_download():
|
|||
video_id = request.form['video_id']
|
||||
try:
|
||||
youtube.download_video(video_id)
|
||||
except ytapi.VideoNotFound:
|
||||
except ycdl.ytapi.VideoNotFound:
|
||||
flask.abort(404)
|
||||
|
||||
return make_json_response({'video_id': video_id, 'state': 'downloaded'})
|
|
@ -1,3 +1,6 @@
|
|||
import logging
|
||||
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)
|
||||
|
||||
import gevent.monkey
|
||||
gevent.monkey.patch_all()
|
||||
|
||||
|
@ -5,7 +8,7 @@ import gevent.pywsgi
|
|||
import gevent.wsgi
|
||||
import sys
|
||||
|
||||
import ycdl_site
|
||||
import ycdl_flask
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
port = int(sys.argv[1])
|
||||
|
@ -15,14 +18,14 @@ else:
|
|||
if port == 443:
|
||||
http = gevent.pywsgi.WSGIServer(
|
||||
listener=('', port),
|
||||
application=ycdl_site.site,
|
||||
application=ycdl_flask.site,
|
||||
keyfile='https\\flasksite.key',
|
||||
certfile='https\\flasksite.crt',
|
||||
)
|
||||
else:
|
||||
http = gevent.pywsgi.WSGIServer(
|
||||
listener=('', port),
|
||||
application=ycdl_site.site,
|
||||
listener=('0.0.0.0', port),
|
||||
application=ycdl_flask.site,
|
||||
)
|
||||
|
||||
|
|
@ -5,7 +5,6 @@ session with these variables preloaded.
|
|||
|
||||
import bot
|
||||
import ycdl
|
||||
import ytapi
|
||||
|
||||
youtube_core = ytapi.Youtube(bot.YOUTUBE_KEY)
|
||||
youtube_core = ycdl.ytapi.Youtube(bot.YOUTUBE_KEY)
|
||||
youtube = ycdl.YCDL(youtube_core)
|
45
utilities/ytqueue.py
Normal file
45
utilities/ytqueue.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
'''
|
||||
I was having trouble making my Flask server perform the youtube-dl without
|
||||
clogging up the other site activities. So instead I'll just have the server
|
||||
export ytqueue files, which this script will download as a separate process.
|
||||
|
||||
Rather than maintaining a text file or database of IDs to be downloaded,
|
||||
I'm fine with creating each ID as a file and letting the filesystem act
|
||||
as the to-do list.
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
YOUTUBE_DL = 'youtube-dlw https://www.youtube.com/watch?v={id}'
|
||||
|
||||
def ytqueue(only_once=False):
|
||||
while True:
|
||||
print(time.strftime('%H:%M:%S'), 'Looking for files.')
|
||||
queue = [f for f in os.listdir() if f.endswith('.ytqueue')]
|
||||
for filename in queue:
|
||||
yt_id = filename.split('.')[0]
|
||||
command = YOUTUBE_DL.format(id=yt_id)
|
||||
exit_code = os.system(command)
|
||||
if exit_code == 0:
|
||||
os.remove(filename)
|
||||
if only_once:
|
||||
break
|
||||
time.sleep(10)
|
||||
|
||||
def ytqueue_argparse(args):
|
||||
return ytqueue(only_once=args.once)
|
||||
|
||||
def main(argv):
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('--once', dest='once', action='store_true')
|
||||
parser.set_defaults(func=ytqueue_argparse)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
args.func(args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
|
@ -2,10 +2,11 @@ import logging
|
|||
import os
|
||||
import sqlite3
|
||||
|
||||
import ytapi
|
||||
from . import helpers
|
||||
from . import ytapi
|
||||
|
||||
def YOUTUBE_DL_COMMAND(video_id):
|
||||
path = 'C:\\Incoming\\ytqueue\\{id}.ytqueue'.format(id=video_id)
|
||||
path = 'D:\\Incoming\\ytqueue\\{id}.ytqueue'.format(id=video_id)
|
||||
open(path, 'w')
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
@ -207,6 +208,12 @@ class YCDL:
|
|||
channels.sort(key=lambda x: x['name'].lower())
|
||||
return channels
|
||||
|
||||
def get_video(self, video_id):
|
||||
self.cur.execute('SELECT * FROM videos WHERE id == ?', [video_id])
|
||||
video = self.cur.fetchone()
|
||||
video = {key: video[SQL_VIDEO[key]] for key in SQL_VIDEO}
|
||||
return video
|
||||
|
||||
def get_videos(self, channel_id=None, download_filter=None):
|
||||
wheres = []
|
||||
bindings = []
|
|
@ -1,7 +1,7 @@
|
|||
import apiclient.discovery
|
||||
import datetime
|
||||
|
||||
import helpers
|
||||
from . import helpers
|
||||
|
||||
class VideoNotFound(Exception):
|
||||
pass
|
24
ytqueue.py
24
ytqueue.py
|
@ -1,24 +0,0 @@
|
|||
'''
|
||||
I was having trouble making my Flask server perform the youtube-dl without
|
||||
clogging up the other site activities. So instead I'll just have the server
|
||||
export ytqueue files, which this script will download as a separate process.
|
||||
|
||||
Rather than maintaining a text file or database of IDs to be downloaded,
|
||||
I'm fine with creating each ID as a file and letting the filesystem act
|
||||
as the to-do list.
|
||||
'''
|
||||
import os
|
||||
import time
|
||||
|
||||
YOUTUBE_DL = 'youtube-dlw https://www.youtube.com/watch?v={id}'
|
||||
|
||||
while True:
|
||||
print(time.strftime('%H:%M:%S'), 'Looking for files.')
|
||||
queue = [f for f in os.listdir() if f.endswith('.ytqueue')]
|
||||
for filename in queue:
|
||||
yt_id = filename.split('.')[0]
|
||||
command = YOUTUBE_DL.format(id=yt_id)
|
||||
exit_code = os.system(command)
|
||||
if exit_code == 0:
|
||||
os.remove(filename)
|
||||
time.sleep(10)
|
Loading…
Reference in a new issue