It's been a while

This commit is contained in:
voussoir 2017-10-08 21:39:07 -07:00
parent 72e121d585
commit ba1961349c
19 changed files with 117 additions and 66 deletions

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -77,15 +77,15 @@
onclick="refresh_channel('{{channel['id']}}', false, function(){location.reload()})">Refresh new videos</button></span> onclick="refresh_channel('{{channel['id']}}', false, function(){location.reload()})">Refresh new videos</button></span>
<span><button class="refresh_button" <span><button class="refresh_button"
onclick="refresh_channel('{{channel['id']}}', true, function(){location.reload()})">Refresh everything</button></span> 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']}}{{query_string}}">All</a></span>
<span><a href="/channel/{{channel['id']}}/pending">Pending</a></span> <span><a href="/channel/{{channel['id']}}/pending{{query_string}}">Pending</a></span>
<span><a href="/channel/{{channel['id']}}/ignored">Ignored</a></span> <span><a href="/channel/{{channel['id']}}/ignored{{query_string}}">Ignored</a></span>
<span><a href="/channel/{{channel['id']}}/downloaded">Downloaded</a></span> <span><a href="/channel/{{channel['id']}}/downloaded{{query_string}}">Downloaded</a></span>
{% else %} {% else %}
<span><a href="/videos">All</a></span> <span><a href="/videos{{query_string}}">All</a></span>
<span><a href="/videos/pending">Pending</a></span> <span><a href="/videos/pending{{query_string}}">Pending</a></span>
<span><a href="/videos/ignored">Ignored</a></span> <span><a href="/videos/ignored{{query_string}}">Ignored</a></span>
<span><a href="/videos/downloaded">Downloaded</a></span> <span><a href="/videos/downloaded{{query_string}}">Downloaded</a></span>
{% endif %} {% endif %}
<span>{{videos|length}} items</span> <span>{{videos|length}} items</span>

View file

@ -0,0 +1,3 @@
from . import ycdl_flask
site = ycdl_flask.site

View file

@ -2,22 +2,36 @@
Do not execute this file directly. Do not execute this file directly.
Use ycdl_launch.py to start the server with gevent. Use ycdl_launch.py to start the server with gevent.
''' '''
import logging
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)
import datetime import datetime
import flask import flask
from flask import request from flask import request
import json import json
import mimetypes import mimetypes
import os import os
import traceback
import bot import bot
import helpers
import ycdl 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) 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( site.config.update(
SEND_FILE_MAX_AGE_DEFAULT=180, SEND_FILE_MAX_AGE_DEFAULT=180,
TEMPLATES_AUTO_RELOAD=True, TEMPLATES_AUTO_RELOAD=True,
@ -91,7 +105,7 @@ def send_file(filepath):
if request.method == 'HEAD': if request.method == 'HEAD':
outgoing_data = bytes() outgoing_data = bytes()
else: 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( response = flask.Response(
outgoing_data, outgoing_data,
@ -112,8 +126,8 @@ def root():
@site.route('/favicon.ico') @site.route('/favicon.ico')
@site.route('/favicon.png') @site.route('/favicon.png')
def favicon(): def favicon():
filename = os.path.join('static', 'favicon.png') return flask.send_file(FAVICON_PATH.absolute_path)
return flask.send_file(filename)
@site.route('/channels') @site.route('/channels')
def get_channels(): def get_channels():
@ -123,24 +137,30 @@ def get_channels():
return flask.render_template('channels.html', channels=channels) return flask.render_template('channels.html', channels=channels)
@site.route('/videos') @site.route('/videos')
@site.route('/watch')
@site.route('/videos/<download_filter>') @site.route('/videos/<download_filter>')
@site.route('/channel/<channel_id>') @site.route('/channel/<channel_id>')
@site.route('/channel/<channel_id>/<download_filter>') @site.route('/channel/<channel_id>/<download_filter>')
def get_channel(channel_id=None, download_filter=None): def get_channel(channel_id=None, download_filter=None):
if channel_id is not None: if channel_id is not None:
try:
youtube.add_channel(channel_id) youtube.add_channel(channel_id)
except Exception:
traceback.print_exc()
channel = youtube.get_channel(channel_id) channel = youtube.get_channel(channel_id)
if channel is None:
flask.abort(404)
else: else:
channel = None channel = None
videos = youtube.get_videos(channel_id=channel_id, download_filter=download_filter) videos = youtube.get_videos(channel_id=channel_id, download_filter=download_filter)
search_term = request.args.get('q', None) search_terms = request.args.get('q', '').lower().strip().replace('+', ' ').split()
if search_term is not None: if search_terms:
search_term = search_term.lower() videos = [v for v in videos if all(term in v['title'].lower() for term in search_terms)]
videos = [v for v in videos if search_term in v['title'].lower()]
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) limit = request.args.get('limit', None)
if limit is not 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 = datetime.datetime.utcfromtimestamp(published)
published = published.strftime('%Y %m %d') published = published.strftime('%Y %m %d')
video['_published_str'] = published video['_published_str'] = published
return flask.render_template('channel.html', channel=channel, videos=videos) return flask.render_template(
'channel.html',
@site.route('/static/<filename>') channel=channel,
def get_static(filename): videos=videos,
filename = filename.replace('\\', os.sep) query_string='?' + request.query_string.decode('utf-8'),
filename = filename.replace('/', os.sep) )
filename = os.path.join('static', filename)
return flask.send_file(filename)
@site.route('/mark_video_state', methods=['POST']) @site.route('/mark_video_state', methods=['POST'])
def post_mark_video_state(): def post_mark_video_state():
@ -184,7 +202,7 @@ def post_mark_video_state():
@site.route('/refresh_all_channels', methods=['POST']) @site.route('/refresh_all_channels', methods=['POST'])
def post_refresh_all_channels(): def post_refresh_all_channels():
force = request.form.get('force', False) force = request.form.get('force', False)
force = helpers.truthystring(force) force = ycdl.helpers.truthystring(force)
youtube.refresh_all_channels(force=force) youtube.refresh_all_channels(force=force)
return make_json_response({}) return make_json_response({})
@ -204,7 +222,7 @@ def post_refresh_channel():
flask.abort(404) flask.abort(404)
force = request.form.get('force', False) force = request.form.get('force', False)
force = helpers.truthystring(force) force = ycdl.helpers.truthystring(force)
youtube.refresh_channel(channel_id, force=force) youtube.refresh_channel(channel_id, force=force)
return make_json_response({}) return make_json_response({})
@ -215,7 +233,7 @@ def post_start_download():
video_id = request.form['video_id'] video_id = request.form['video_id']
try: try:
youtube.download_video(video_id) youtube.download_video(video_id)
except ytapi.VideoNotFound: except ycdl.ytapi.VideoNotFound:
flask.abort(404) flask.abort(404)
return make_json_response({'video_id': video_id, 'state': 'downloaded'}) return make_json_response({'video_id': video_id, 'state': 'downloaded'})

View file

@ -1,3 +1,6 @@
import logging
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)
import gevent.monkey import gevent.monkey
gevent.monkey.patch_all() gevent.monkey.patch_all()
@ -5,7 +8,7 @@ import gevent.pywsgi
import gevent.wsgi import gevent.wsgi
import sys import sys
import ycdl_site import ycdl_flask
if len(sys.argv) == 2: if len(sys.argv) == 2:
port = int(sys.argv[1]) port = int(sys.argv[1])
@ -15,14 +18,14 @@ else:
if port == 443: if port == 443:
http = gevent.pywsgi.WSGIServer( http = gevent.pywsgi.WSGIServer(
listener=('', port), listener=('', port),
application=ycdl_site.site, application=ycdl_flask.site,
keyfile='https\\flasksite.key', keyfile='https\\flasksite.key',
certfile='https\\flasksite.crt', certfile='https\\flasksite.crt',
) )
else: else:
http = gevent.pywsgi.WSGIServer( http = gevent.pywsgi.WSGIServer(
listener=('', port), listener=('0.0.0.0', port),
application=ycdl_site.site, application=ycdl_flask.site,
) )

View file

@ -5,7 +5,6 @@ session with these variables preloaded.
import bot import bot
import ycdl import ycdl
import ytapi
youtube_core = ytapi.Youtube(bot.YOUTUBE_KEY) youtube_core = ycdl.ytapi.Youtube(bot.YOUTUBE_KEY)
youtube = ycdl.YCDL(youtube_core) youtube = ycdl.YCDL(youtube_core)

45
utilities/ytqueue.py Normal file
View 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:])

View file

@ -2,10 +2,11 @@ import logging
import os import os
import sqlite3 import sqlite3
import ytapi from . import helpers
from . import ytapi
def YOUTUBE_DL_COMMAND(video_id): 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') open(path, 'w')
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
@ -207,6 +208,12 @@ class YCDL:
channels.sort(key=lambda x: x['name'].lower()) channels.sort(key=lambda x: x['name'].lower())
return channels 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): def get_videos(self, channel_id=None, download_filter=None):
wheres = [] wheres = []
bindings = [] bindings = []

View file

@ -1,7 +1,7 @@
import apiclient.discovery import apiclient.discovery
import datetime import datetime
import helpers from . import helpers
class VideoNotFound(Exception): class VideoNotFound(Exception):
pass pass

View file

@ -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)