Add YouTube downloader

This commit is contained in:
Kumi 2019-02-18 17:23:47 +01:00
parent dc8bb46734
commit 28ea47c961
No known key found for this signature in database
GPG key ID: 8D4E139A5FF9082F
6 changed files with 94 additions and 19 deletions

View file

@ -3,11 +3,13 @@
import re import re
import importlib import importlib
import argparse import argparse
import subprocess
regs = { regs = {
"\d/\d/\d_\d\.jpg": "krpanosteal", "\d/\d/\d_\d\.jpg": "krpanosteal",
"pano\_[frblud].jpg": "krpanosteal", "pano\_[frblud].jpg": "krpanosteal",
"my.matterport.com/show/": "matterportsteal" "my.matterport.com/show/": "matterportsteal",
"youtube.com": "youtubesteal"
} }
@ -29,18 +31,27 @@ def parse_url(url):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('url', help='URL to process') parser.add_argument('url', help='URL to process')
parser.add_argument('--title', help='title to be used for the file name') parser.add_argument('--title', help='title to be used for the file name', default="No Title")
parser.add_argument("--rotation", nargs=3, type=int, help="rotation on x/y/z axes", metavar=("x","y","z")) parser.add_argument("--rotation", nargs=3, type=int, help="rotation on x/y/z axes", metavar=("x","y","z"))
parser.add_argument("--resolution", type=int, nargs=2, metavar=("w","h")) parser.add_argument("--resolution", type=int, nargs=2, metavar=("w","h"))
parser.add_argument("--output") parser.add_argument("--output", default=".")
args = parser.parse_args() args = parser.parse_args()
try: try:
handler = parse_url(args.url) handler = parse_url(args.url)
image = handler(args.url, args.rotation or [0,0,0], args.resolution or [3840, 1920]) image = handler(args.url, args.rotation or [0,0,0], args.resolution or [3840, 1920])
if not hasattr(image, "im"):
with open(args.output + "/" + args.title + ".mkv", "wb") as video:
video.write(image)
subprocess.run(["/usr/bin/ffmpeg",
"-i", args.output + "/" + args.title + ".mkv",
"-ss", "00:00:10",
"-vframes", "1",
"-f", "image2",
args.output + "/" + args.title + ".thumb.jpg"])
else:
image.save(args.output + "/" + args.title + ".png") image.save(args.output + "/" + args.title + ".png")
except Exception as e: except Exception as e:
with open(args.output + "/" + args.title + ".err", "w") as errorfile: with open(args.output + "/" + args.title + ".err", "w") as errorfile:
errorfile.write("") errorfile.write(str(e))

2
run.sh
View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
mkdir /tmp/panosteal/ -p mkdir /tmp/panosteal/youtube -p
gunicorn -c gunicorn.cfg server.daemon gunicorn -c gunicorn.cfg server.daemon

View file

@ -22,6 +22,8 @@ JSON = "application/json"
XML = "text/xml" XML = "text/xml"
TEXT = "text/plain" TEXT = "text/plain"
PNG = "image/png" PNG = "image/png"
MKV = "video/mkv"
JPG = "image/jpeg"
def static(req): def static(req):
try: try:
@ -92,15 +94,15 @@ def addjob(req):
return Response(status, ctype, content) return Response(status, ctype, content)
def getjob(req): def getjob(req):
jobid = req.path[-1] jobid = req.path[-1].rstrip("-thumb").rstrip("-info")
content_disposition = None content_disposition = None
found = glob.glob("/tmp/panosteal/%s---*.png" % jobid) found = (glob.glob("/tmp/panosteal/%s---*.png" % jobid) + glob.glob("/tmp/panosteal/%s---*.mkv" % jobid)) if not req.path[-1].endswith("thumb") else glob.glob("/tmp/panosteal/%s---*.jpg" % jobid)
if found: if found:
md5 = "Not happening." md5 = "Not happening."
while True: while True:
content = open(found[0], "rb").read() content = open(found[0], "rb").read() if not req.path[-1].endswith("info") else b""
newmd5 = hashlib.md5(content).hexdigest() newmd5 = hashlib.md5(content).hexdigest()
if newmd5 == md5: if newmd5 == md5:
break break
@ -108,8 +110,8 @@ def getjob(req):
time.sleep(0.5) time.sleep(0.5)
code = HTTP200 code = HTTP200
ctype = PNG ctype = PNG if found[0].endswith(".png") else JPG if found[0].endswith(".jpg") else MKV
content_disposition = found[0].split("---")[-1] content_disposition = found[0].split("---")[-1] if not req.path[-1].endswith("info") else None
elif glob.glob("/tmp/panosteal/%s*err" % jobid): elif glob.glob("/tmp/panosteal/%s*err" % jobid):
content = "<h1>500 Internal Server Error</h1>".encode() content = "<h1>500 Internal Server Error</h1>".encode()

View file

@ -24,7 +24,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<form class="" id="theform"> <form class="" id="theform">
<div class="form-group"> <label>URL</label> <input type="text" class="form-control" placeholder="https://example.com/0/0/0_0.jpg" name="url" required="required"> <small class="form-text text-muted">URL of an image contained in a krpano panorama or of a website containing a Matterport panorama</small> </div> <div class="form-group"> <label>URL</label> <input type="text" class="form-control" placeholder="https://example.com/0/0/0_0.jpg" name="url" required="required">
<div class="form-group"> <label>Title</label> <input type="" class="form-control" placeholder="1234 - Shiny Place" id="title" name="title"> </div> <div class="form-group"> <label>Title</label> <input type="" class="form-control" placeholder="1234 - Shiny Place" id="title" name="title"> </div>
<div class="form-group"> <label style="display: block;">Resolution</label> <input type="" class="form-control" placeholder="3840" name="width" style="width: 100px; display: inline;"> x <input type="" class="form-control" placeholder="1920" name="height" style="width: 100px; display: inline;"> </div> <div class="form-group"> <label style="display: block;">Resolution</label> <input type="" class="form-control" placeholder="3840" name="width" style="width: 100px; display: inline;"> x <input type="" class="form-control" placeholder="1920" name="height" style="width: 100px; display: inline;"> </div>
<div id="options"> <div id="options">

View file

@ -37,11 +37,23 @@ function failcard(jobid, title) {
} }
function finishcard(jobid, title) { function finishcard(jobid, title, video) {
deletecard(jobid); deletecard(jobid);
if (!video) {
var text = '<div class="col-sm-3" id="' + jobid + '"> <div class="card"> <img class="card-img-top img-fluid" src="/getjob/' + jobid + '" alt="Final Image"><div style="text-align: center; font-weight: bold;" class="card-block">' + title + '</div> <div style="text-align: center; color: white;" class="card-block"> <a href="/getjob/' + jobid + '" class="btn btn-primary">Download</a> <a onclick="deletecard(\'' + jobid + '\');" class="btn btn-danger">Hide</a></div> </div> </div>'; var text = '<div class="col-sm-3" id="' + jobid + '"> <div class="card"> <img class="card-img-top img-fluid" src="/getjob/' + jobid + '" alt="Final Image"><div style="text-align: center; font-weight: bold;" class="card-block">' + title + '</div> <div style="text-align: center; color: white;" class="card-block"> <a href="/getjob/' + jobid + '" class="btn btn-primary">Download</a> <a onclick="deletecard(\'' + jobid + '\');" class="btn btn-danger">Hide</a></div> </div> </div>';
} else {
var text = '<div class="col-sm-3" id="' + jobid + '"> <div class="card"> <img class="card-img-top img-fluid" id="' + jobid + '-thumb" src="/getjob/' + jobid + '-thumb" alt="Final Video"><div style="text-align: center; font-weight: bold;" class="card-block">' + title + '</div> <div style="text-align: center; color: white;" class="card-block"> <a href="/getjob/' + jobid + '" class="btn btn-primary">Download</a> <a onclick="deletecard(\'' + jobid + '\');" class="btn btn-danger">Hide</a></div> </div> </div>';
};
$('#cards').append(text); $('#cards').append(text);
var counter = 0;
var interval = setInterval(function() {
var image = document.getElementById(jobid + '-thumb');
image.src = "/getjob/" + jobid + "-thumb?rand=" + Math.random();
if (++counter === 10) {
window.clearInterval(interval);
}
}, 2000);
} }
$('#theform').submit(function(event){ $('#theform').submit(function(event){
@ -64,16 +76,16 @@ $('#theform').submit(function(event){
$.ajax({ $.ajax({
type: "GET", type: "GET",
cache: false, cache: false,
url: "/getjob/" + jobid, url: "/getjob/" + jobid + "-info",
statusCode: { statusCode: {
404: function() { 404: function() {
clearInterval(interval); clearInterval(interval);
failcard(jobid, title); failcard(jobid, title);
return; return;
}, },
200: function() { 200: function(data, tstatus, xhr) {
clearInterval(interval); clearInterval(interval);
finishcard(jobid, title); finishcard(jobid, title, (xhr.getResponseHeader('content-type') == "image/png") ? false : true);
return; return;
}, },
500: function() { 500: function() {

50
youtubesteal/__init__.py Normal file
View file

@ -0,0 +1,50 @@
import PIL.Image
import urllib.request
import io
import math
import subprocess
import tempfile
import pathlib
import os
import subprocess
import uuid
import glob
from stitching import tiles_to_equirectangular_blender, multistitch
def youtube_get_video(url):
vid = uuid.uuid4().hex
process = subprocess.Popen(
['youtube-dl',
'--user-agent', '""',
'-o', vid,
url,
], cwd="/tmp/panosteal/youtube/"
)
process.wait()
data = open('/tmp/panosteal/youtube/%s.mkv' % vid, 'rb').read()
for i in glob.glob("/tmp/panosteal/youtube/%s*" % vid):
os.remove(i)
return data
def youtube_get_file(yurl):
urllib.request.urlopen(yurl)
def youtube_to_equirectangular(url, rotation=[0,0,0], resolution=[3840,1920]):
'''
Takes the URL of any YouTube video, downloads it and returns the video file.
:param url: YouTube URL
:return: File object containing the video
'''
rx, ry, rz = rotation
width, height = resolution
return youtube_get_video(url)
process_url = youtube_to_equirectangular