2023-06-06 15:18:12 +00:00
|
|
|
from mail import send_email
|
|
|
|
from flask import Flask, abort, render_template, redirect, request, url_for
|
|
|
|
from PIL import Image
|
|
|
|
from proglog import ProgressBarLogger
|
|
|
|
import os
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
import moviepy.editor as moviepy
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
ALLOWED_UPLOAD_EXTENSIONS = {'mp4', 'webm', 'mkv', 'avi', 'ogv'}
|
2023-06-15 18:04:28 +00:00
|
|
|
ALLOWED_CONVERT_EXTENSIONS = {'mp4', 'webm',
|
|
|
|
'mkv', 'avi', 'ogv', 'ogg', 'mp3', 'flac'}
|
2023-06-06 15:18:12 +00:00
|
|
|
AUDIO_EXTENSIONS = {'ogg', 'mp3', 'flac'}
|
2023-06-15 18:04:28 +00:00
|
|
|
ALLOWED_WATERMARK_EXTENSIONS = {
|
|
|
|
'bmp', 'png', 'jpg', 'jpeg', 'tiff', 'tga', 'svg'}
|
2023-06-06 15:18:12 +00:00
|
|
|
|
|
|
|
percentages = {}
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
class BarLogger(ProgressBarLogger):
|
|
|
|
global percentages
|
|
|
|
id = None
|
|
|
|
|
|
|
|
def bars_callback(self, bar, attr, value, old_value=None):
|
|
|
|
percentages[self.id] = (value / self.bars[bar]['total']) * 100
|
|
|
|
|
|
|
|
def __init__(self, id):
|
|
|
|
super(self.__class__, self).__init__()
|
|
|
|
self.id = id
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
def is_integer(n):
|
|
|
|
try:
|
|
|
|
return float(n).is_integer()
|
|
|
|
except ValueError:
|
|
|
|
return False
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
def getExtension(filename, isWatermark=False):
|
|
|
|
if not '.' in filename:
|
|
|
|
return False
|
|
|
|
extension = filename.rsplit('.', 1)[1].lower()
|
|
|
|
if extension in ALLOWED_UPLOAD_EXTENSIONS and not isWatermark:
|
|
|
|
return extension
|
|
|
|
elif extension in ALLOWED_WATERMARK_EXTENSIONS and isWatermark:
|
|
|
|
return extension
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
@app.route('/', methods=['GET', 'POST'])
|
|
|
|
def index():
|
|
|
|
if request.method == 'POST' and 'video' in request.files:
|
|
|
|
file = request.files['video']
|
|
|
|
if not file.filename == '':
|
|
|
|
extension = getExtension(file.filename)
|
|
|
|
if extension != False:
|
|
|
|
filename = str(uuid.uuid4()) + '.' + extension
|
|
|
|
file.save(os.path.join('videos', filename))
|
|
|
|
return redirect(url_for('video', id=filename))
|
|
|
|
else:
|
|
|
|
return render_template('index.html', error='Non-allowed file extension.')
|
|
|
|
|
|
|
|
return render_template('index.html')
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
@app.route('/video', methods=['GET', 'POST'])
|
|
|
|
def video():
|
|
|
|
error = ''
|
|
|
|
changed = False
|
|
|
|
audio = None
|
|
|
|
id = request.args.get('id')
|
2023-06-15 18:04:28 +00:00
|
|
|
if id == None:
|
|
|
|
abort(400)
|
2023-06-06 15:18:12 +00:00
|
|
|
path = os.path.join('videos', id)
|
|
|
|
if id != None and os.path.isfile(path):
|
|
|
|
clip = moviepy.VideoFileClip(path)
|
|
|
|
if request.method == 'POST':
|
|
|
|
start = request.form.get('start')
|
|
|
|
end = request.form.get('end')
|
|
|
|
extension = request.form.get('extension')
|
|
|
|
email = request.form.get('email')
|
|
|
|
if not email:
|
|
|
|
abort(400)
|
|
|
|
if start and end:
|
|
|
|
if is_integer(start) and is_integer(end) and int(start) < int(end):
|
|
|
|
if int(start) < 0 or int(end) > clip.duration:
|
|
|
|
error += 'Selected subclip out of bounds.<br>'
|
|
|
|
else:
|
|
|
|
clip = clip.subclip(start, end)
|
|
|
|
changed = True
|
|
|
|
if extension:
|
|
|
|
if extension in ALLOWED_CONVERT_EXTENSIONS:
|
|
|
|
if extension in AUDIO_EXTENSIONS:
|
|
|
|
audio = clip.audio
|
|
|
|
newId = id.rsplit('.', 1)[0] + '.' + extension
|
|
|
|
if id == newId:
|
|
|
|
error += 'A different extension than the currently used one is needed.<br>'
|
|
|
|
else:
|
|
|
|
changed = True
|
|
|
|
else:
|
|
|
|
error += 'Requested recode extension not allowed.<br>'
|
|
|
|
if 'watermark' in request.files:
|
|
|
|
file = request.files['watermark']
|
|
|
|
if not file.filename == '':
|
|
|
|
if audio:
|
|
|
|
error += 'Audio cannot be watermarked.<br>'
|
|
|
|
else:
|
|
|
|
watermarkExtension = getExtension(file.filename, True)
|
|
|
|
if watermarkExtension:
|
2023-06-15 18:04:28 +00:00
|
|
|
watermarkPath = os.path.join(
|
|
|
|
'videos', id + '-watermark' + '.' + watermarkExtension)
|
2023-06-06 15:18:12 +00:00
|
|
|
file.save(watermarkPath)
|
|
|
|
|
|
|
|
formatter = {'PNG': 'RGBA', 'JPEG': 'RGB'}
|
|
|
|
img = Image.open(watermarkPath)
|
2023-06-15 18:04:28 +00:00
|
|
|
rgbimg = Image.new(formatter.get(
|
|
|
|
img.format, 'RGB'), img.size)
|
2023-06-06 15:18:12 +00:00
|
|
|
rgbimg.paste(img)
|
|
|
|
rgbimg.save(watermarkPath, format=img.format)
|
|
|
|
|
|
|
|
watermark = (moviepy.ImageClip(watermarkPath)
|
2023-06-15 18:04:28 +00:00
|
|
|
.set_duration(clip.duration)
|
|
|
|
.set_pos(('right', 'bottom')))
|
2023-06-06 15:18:12 +00:00
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
clip = moviepy.CompositeVideoClip(
|
|
|
|
[clip, watermark])
|
2023-06-06 15:18:12 +00:00
|
|
|
os.remove(watermarkPath)
|
|
|
|
changed = True
|
|
|
|
else:
|
|
|
|
error += 'Non-allowed watermark extension.<br>'
|
|
|
|
if changed:
|
|
|
|
logger = BarLogger(id)
|
|
|
|
if 'newId' in locals():
|
|
|
|
os.remove(path)
|
|
|
|
id = newId
|
|
|
|
path = os.path.join('videos', id)
|
|
|
|
if audio:
|
|
|
|
audio.write_audiofile(path, logger=logger)
|
|
|
|
else:
|
|
|
|
clip.write_videofile(path, logger=logger)
|
|
|
|
send_email(email, path)
|
|
|
|
os.remove(path)
|
|
|
|
return render_template('success.html', error=error)
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
return render_template('video.html', length=int(clip.duration), error=error)
|
2023-06-06 15:18:12 +00:00
|
|
|
else:
|
|
|
|
abort(404)
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
@app.route('/progress', methods=['GET'])
|
|
|
|
def progress():
|
|
|
|
id = request.args.get('id')
|
|
|
|
percentage = percentages.get(id)
|
|
|
|
if percentage:
|
|
|
|
return str(percentage)
|
|
|
|
else:
|
|
|
|
abort(404)
|
|
|
|
|
2023-06-15 18:04:28 +00:00
|
|
|
|
2023-06-06 15:18:12 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
if not os.path.isdir('videos'):
|
|
|
|
os.mkdir('videos')
|
|
|
|
app.run()
|