Add YouTube downloader
This commit is contained in:
parent
dc8bb46734
commit
28ea47c961
6 changed files with 94 additions and 19 deletions
23
handler.py
23
handler.py
|
@ -3,11 +3,13 @@
|
|||
import re
|
||||
import importlib
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
regs = {
|
||||
"\d/\d/\d_\d\.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__":
|
||||
parser = argparse.ArgumentParser()
|
||||
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("--resolution", type=int, nargs=2, metavar=("w","h"))
|
||||
parser.add_argument("--output")
|
||||
parser.add_argument("--output", default=".")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
handler = parse_url(args.url)
|
||||
image = handler(args.url, args.rotation or [0,0,0], args.resolution or [3840, 1920])
|
||||
|
||||
image.save(args.output + "/" + args.title + ".png")
|
||||
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")
|
||||
except Exception as e:
|
||||
with open(args.output + "/" + args.title + ".err", "w") as errorfile:
|
||||
errorfile.write("")
|
||||
errorfile.write(str(e))
|
||||
|
|
2
run.sh
2
run.sh
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir /tmp/panosteal/ -p
|
||||
mkdir /tmp/panosteal/youtube -p
|
||||
gunicorn -c gunicorn.cfg server.daemon
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ JSON = "application/json"
|
|||
XML = "text/xml"
|
||||
TEXT = "text/plain"
|
||||
PNG = "image/png"
|
||||
MKV = "video/mkv"
|
||||
JPG = "image/jpeg"
|
||||
|
||||
def static(req):
|
||||
try:
|
||||
|
@ -92,15 +94,15 @@ def addjob(req):
|
|||
return Response(status, ctype, content)
|
||||
|
||||
def getjob(req):
|
||||
jobid = req.path[-1]
|
||||
jobid = req.path[-1].rstrip("-thumb").rstrip("-info")
|
||||
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:
|
||||
md5 = "Not happening."
|
||||
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()
|
||||
if newmd5 == md5:
|
||||
break
|
||||
|
@ -108,8 +110,8 @@ def getjob(req):
|
|||
time.sleep(0.5)
|
||||
|
||||
code = HTTP200
|
||||
ctype = PNG
|
||||
content_disposition = found[0].split("---")[-1]
|
||||
ctype = PNG if found[0].endswith(".png") else JPG if found[0].endswith(".jpg") else MKV
|
||||
content_disposition = found[0].split("---")[-1] if not req.path[-1].endswith("info") else None
|
||||
|
||||
elif glob.glob("/tmp/panosteal/%s*err" % jobid):
|
||||
content = "<h1>500 Internal Server Error</h1>".encode()
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<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 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">
|
||||
|
|
|
@ -37,11 +37,23 @@ function failcard(jobid, title) {
|
|||
}
|
||||
|
||||
|
||||
function finishcard(jobid, title) {
|
||||
function finishcard(jobid, title, video) {
|
||||
deletecard(jobid);
|
||||
|
||||
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>';
|
||||
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>';
|
||||
} 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);
|
||||
|
||||
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){
|
||||
|
@ -64,16 +76,16 @@ $('#theform').submit(function(event){
|
|||
$.ajax({
|
||||
type: "GET",
|
||||
cache: false,
|
||||
url: "/getjob/" + jobid,
|
||||
url: "/getjob/" + jobid + "-info",
|
||||
statusCode: {
|
||||
404: function() {
|
||||
clearInterval(interval);
|
||||
failcard(jobid, title);
|
||||
return;
|
||||
},
|
||||
200: function() {
|
||||
200: function(data, tstatus, xhr) {
|
||||
clearInterval(interval);
|
||||
finishcard(jobid, title);
|
||||
finishcard(jobid, title, (xhr.getResponseHeader('content-type') == "image/png") ? false : true);
|
||||
return;
|
||||
},
|
||||
500: function() {
|
||||
|
|
50
youtubesteal/__init__.py
Normal file
50
youtubesteal/__init__.py
Normal 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
|
Loading…
Reference in a new issue