示例#1
0
def on_worker_ready(**kwargs):
    encoding_videos = db_session.query(models.Video).filter_by(status='encoding').all()
    for video in encoding_videos:
        transcode.delay(video.id)

    start_encoding_videos = db_session.query(models.Video).filter_by(status='start-encoding').all()
    for video in start_encoding_videos:
        transcode.delay(video.id)
示例#2
0
    def get(self, video_id, subtitle_id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()
        subtitle = db_session.query(models.Subtitle).filter_by(
            id=subtitle_id, video_id=video_id).one_or_none()

        if not video:
            abort(404, 'Video not found')

        if not subtitle:
            abort(404, 'Subtitle not found')

        return subtitle
示例#3
0
    def delete(self, video_id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()

        if not video:
            abort(404, 'Video not found')

        if video.status in ['encoding', 'start-encoding']:
            abort(409, 'Cannot delete while encoding')

        try:
            if (video.playlist):
                rm_f(video.playlist)

            if (video.orig_file):
                rm_f(os.path.join(app.config['MOVIE_PATH'], video.orig_file))

            if app.config['STORAGE_BACKEND'] == 'S3':
                tasks.s3_delete.delay(video.id)
            else:
                viddir = f"{app.config['MOVIE_PATH']}/{video.id}"
                shutil.rmtree(viddir, ignore_errors=True)
        except:
            abort(500)

        db_session.delete(video)
        db_session.commit()

        return {'message': 'Video deleted'}, 204
示例#4
0
    def create_stream(self, command, filename, stream_type):
        outfile = f'{self.outdir}/{filename}'
        command_hash = hashlib.sha256(str(command).encode('utf-8')).hexdigest()

        encoded_files = db_session.query(models.EncodedFile).filter_by(
            video_id = self.video.id,
            encoded_file_name = filename,
        ).all()

        encoded_file = None

        for file in encoded_files:
            if file.encoding_hash != command_hash:
                db_session.delete(file)
                db_session.commit()
                encoded_file = None
            else:
                encoded_file = file

        if not encoded_file:
            encoded_file = models.EncodedFile(
                video_id = self.video.id,
                encoded_file_name = filename,
                encoding_hash = command_hash,
                track_type = stream_type
            )

            self.encoded_files.append(encoded_file)
            self.ffmpeg_command.extend(command)
            self.ffmpeg_command.append(outfile)
            self.has_work = True
示例#5
0
def chat(video_id):
    video = db_session.query(models.Video).filter_by(id=video_id).one_or_none()

    if not video:
        abort(404, "Video not found")

    return render_template("chat.html", video = video)
示例#6
0
def on_join(data):
    print(
        f"Client logged on, username:{data['username']}, room:{data['room']}")
    if data['room'] not in rooms.keys():
        video = db_session.query(
            models.Video).filter_by(id=data['room']).one_or_none()
        rooms[data['room']] = Room(data['room'], video)

    roomname = data['room']
    room = rooms[roomname]

    username = html.escape(data['username'])

    new_user = room.join(request.sid, username)
    join_room(roomname)
    timer = rooms[roomname].timer

    emit('connected', {
        'time': timer.get(),
        'state': timer.running,
        'username': room.last
    })
    if new_user:
        emit('joined', {'username': username},
             room=roomname,
             include_self=False)
示例#7
0
    def delete(self, id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(owner=owner_id,
                                                         id=id).one_or_none()

        if not video:
            abort(404)

        try:
            if (video.playlist):
                rm_f(video.playlist)

            if (video.orig_file):
                rm_f(os.path.join(app.config['MOVIE_PATH'], video.orig_file))

            if app.config['STORAGE_BACKEND'] == 'S3':
                tasks.s3_delete.delay(video.id)
            else:
                viddir = f"{app.config['MOVIE_PATH']}/{video.id}"
                shutil.rmtree(viddir, ignore_errors=True)
        except:
            abort(500)

        db_session.delete(video)
        db_session.commit()

        return "Video deleted", 204
示例#8
0
def transcode(self, video_id):
    video = db_session.query(models.Video).filter_by(id=video_id).one_or_none()
    video.status = 'encoding'
    db_session.commit()

    outdir = f"{celery.conf.get('MOVIE_PATH')}/{video.id}"
    try:
        os.mkdir(outdir)
    except FileExistsError:
        pass

    try:
        ffmpeg = FfmpegTranscode(video, self, outdir)
        ffmpeg.run()
        transcode_video(video, self)
    except FfmpegException as e:
        video.status = 'error'
        video.status_message = str(e)
        db_session.commit()

        self.update_state(
            state = states.FAILURE,
            meta = str(e)
        )

        raise Ignore()
示例#9
0
def update_video(video_id):
    video = db_session.query(models.Video).filter_by(owner=owner_id, id=video_id).one_or_none()
    if not video:
        return make_response("Video not found", 404)
    
    if request.method == "GET":
        return render_template("video.html", video = video)
示例#10
0
    def get(self, id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(owner=owner_id,
                                                         id=id).one_or_none()

        if not video:
            abort(404)

        return video
示例#11
0
    def post(self, video_id, subtitle_id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()
        subtitle = db_session.query(models.Subtitle).filter_by(
            id=subtitle_id, video_id=video_id).one_or_none()

        if not video:
            abort(404, 'Video not found')

        if not subtitle:
            abort(404, 'Subtitle not found')

        file = request.files['file']
        filename = f'{video.id}_sub_{subtitle.id}_orig'
        file.save(os.path.join(app.config['MOVIE_PATH'], filename))
        subtitle.orig_file_name = filename
        db_session.commit()
示例#12
0
    def post(self, video_id, subtitle_id):
        args = new_subtitle_parser.parse_args()

        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()
        subtitle = db_session.query(models.Subtitle).filter_by(
            id=subtitle_id, video_id=video_id).one_or_none()

        if not video:
            abort(404, 'Video not found')

        if not subtitle:
            abort(404, 'Subtitle not found')

        subtitle.title = args['title']
        subtitle.language = args['language']
        db_session.commit()

        return subtitle
示例#13
0
def watch(video_id):
    video = db_session.query(models.Video).filter_by(id=video_id).one_or_none()

    if not video:
        abort(404, "Video not found")

    print("playlist: " + video.playlist)
    baseurl = "/static/movies/"
    if app.config['STORAGE_BACKEND'] == 'S3':
        baseurl = app.config['S3_BUCKET_URL']
        if not baseurl.endswith("/"):
            baseurl = baseurl + "/"
    
    return render_template("watch.html", baseurl = baseurl, video = video)
示例#14
0
    def post(self, video_id):
        args = video_parser.parse_args()

        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()

        if not video:
            abort(404, 'Video not found')

        if args.get('title'):
            if not video.status in ['start-encoding', 'encoding']:
                video.title = args.get('title')
            else:
                abort(409, 'Cannot change video title while encoding')

        if args.get('tune'):
            if not video.status in ['start-encoding', 'encoding']:
                video.tune = args.get('tune')
            else:
                abort(409, 'Cannot change video tuning while encoding')

        if args.get('status'):
            status = args.get('status')
            if status == 'file-waiting':
                if not video.status in ['encoding', 'start-encoding']:
                    video.status = status
                    video.upload_identifier = None
                else:
                    abort(409, 'Cannot upload new file while encoding')

            if status == 'start-encoding':
                if video.status in ['file-uploaded', 'ready', 'error']:
                    video.status = status
                    video.encoding_progress = 0
                    video.status_error = ""
                    video.celery_taskid = tasks.transcode.delay(video.id)
                else:
                    abort(
                        409,
                        'Cannot start encoding while video is in this state')

        db_session.commit()

        return video
示例#15
0
    def get(self, video_id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()

        if not video:
            return {'message': 'Video not found'}, 403

        resumableTotalChunks = request.args.get('resumableTotalChunks',
                                                type=int)
        resumableChunkNumber = request.args.get('resumableChunkNumber',
                                                default=1,
                                                type=int)
        resumableIdentifier = request.args.get('resumableIdentifier',
                                               default='error',
                                               type=str)
        resumableFilename = request.args.get('resumableFilename',
                                             default='error',
                                             type=str)
        resumableChunkSize = request.args.get('resumableChunkSize',
                                              default=0,
                                              type=int)

        target_file_name = target_name(video.id)

        if not resumableIdentifier or not resumableChunkNumber or not resumableChunkSize:
            return {'message': 'Parameter error'}, 500

        if video.upload_identifier != resumableIdentifier:
            return {'message': 'Unknown uploader session'}, 404

        if video.orig_file_name != resumableFilename:
            return {'message': 'Different filename'}, 404

        if not target_file_name.exists():
            return {'message': 'Chunk not found'}, 404

        with open(target_file_name, "rb") as target_file:
            offset = (resumableChunkNumber - 1) * resumableChunkSize
            fh = target_file.fileno()
            if not is_hole(fh, offset):
                return 'OK'

        return {'message': 'Chunk not found'}, 404
示例#16
0
    def put(self, video_id):
        args = new_subtitle_parser.parse_args()

        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        if not owner_id:
            abort(403)

        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()
        if not video:
            abort(404, 'Video not found')

        subtitle = models.Subtitle(
            video_id=video.id,
            language=args['language'],
            title=args['title'],
        )

        db_session.add(subtitle)
        db_session.commit()

        return subtitle
示例#17
0
def resumable(video_id):
    video = db_session.query(models.Video).filter_by(
        owner=owner_id, id=video_id).one_or_none()
    if not video:
        return abort(403, "Video not found")

    resumableIdentfier = request.args.get('resumableIdentifier', type=str)
    resumableChunkNumber = request.args.get('resumableChunkNumber', type=int)

    if not resumableIdentfier or not resumableChunkNumber:
        # Parameters are missing or invalid
        abort(500, 'Parameter error')

    # chunk path based on the parameters
    chunk_file = os.path.join(app.config['MOVIE_PATH'], video_id, 'tmp',
                              get_chunk_name('orig', resumableChunkNumber))
    app.logger.debug('Getting chunk: %s', chunk_file)

    if os.path.isfile(chunk_file):
        # Let resumable.js know this chunk already exists
        return 'OK'
    else:
        # Let resumable.js know this chunk does not exists and needs to be uploaded
        abort(404, 'Not found')
示例#18
0
def transcode_video(video, task):
    status = 'error'
    output = ""

    outdir = f"{celery.conf.get('MOVIE_PATH')}/{video.id}"
    try:
        os.mkdir(outdir)
    except FileExistsError:
        pass

    master_playlist = f"{outdir}/playlist.mpd"
    rm_f(master_playlist)

    dash_size = 4
    dash_command = ['MP4Box', '-dash', f'{dash_size * 1000}', '-rap', '-frag-rap', '-min-buffer', '16000', '-profile', 'dashavc264:onDemand', '-mpd-title', video.title ,'-out', master_playlist]
    try:
        print("Reencoded file")

        def sort_video(video):
            return int(video.split("_")[1])

        def sort_audio(audio):
            return int(audio.split("_")[1].split("k")[0])

        video_files = []
        encoded_files = db_session.query(models.EncodedFile).filter_by(video_id = video.id, track_type='video').all()
        for encoded_file in encoded_files:
            video_files.append(f'{outdir}/{encoded_file.encoded_file_name}')
        video_files.sort(key=sort_video)

        audio_files = []
        encoded_files = db_session.query(models.EncodedFile).filter_by(video_id = video.id, track_type='audio').all()
        for encoded_file in encoded_files:
            audio_files.append(f'{outdir}/{encoded_file.encoded_file_name}')
        audio_files.sort(key=sort_audio)

        dash_command.extend(video_files)
        dash_command.extend(audio_files)

        print(f'Executing: {" ".join(dash_command)}')
        output = subprocess.check_call(dash_command, stderr=subprocess.STDOUT)
        print("DASHed file")

        status = 'ready'

    except Exception as e:
        print(output)
        print(e)
        video.status = 'error'
        video.status_message = 'MP4Box failed'
        db_session.commit()

    if celery.conf.get('STORAGE_BACKEND') == "S3":
        print("Uploading to S3")

        nthreads = celery.conf.get('S3_UPLOAD_THREADS')
        g = glob.glob(f"{outdir}/*")
        splits = numpy.array_split(g, nthreads)
        threads = list()

        for index in range(nthreads):
            x = threading.Thread(target=s3_upload, args=(splits[index].copy(),))
            threads.append(x)
            x.start()

        for index, thread in enumerate(threads):
            thread.join()

        print("Done uploading")

    video.playlist = f'{video.id}/playlist.mpd'
    video.encoding_progress = 100
    video.status = status
    db_session.commit()
示例#19
0
 def get(self):
     owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
     res = db_session.query(models.Video).filter_by(owner=owner_id).all()
     return res
示例#20
0
 def get(self, video_id):
     owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
     video = db_session.query(models.Video).filter_by(
         owner=owner_id, id=video_id).one_or_none()
     return video.subtitles
示例#21
0
def transcode(tmpfile, streaminfo, video_id):
    status = 'error'
    output = ""

    outdir = f"{celery.conf.get('MOVIE_PATH')}/{video_id}"
    shutil.rmtree(outdir, ignore_errors=True)
    os.mkdir(outdir)

    master_playlist = f"{outdir}/playlist.mpd"
    rm_f(master_playlist)

    vwidth = 0
    vheight = 0
    duration = 0
    acodec = ""
    vcodec = ""
    framerate = 24
    chunk_size = 4

    video_streamidx = -1
    audio_streamidx = -1
    has_audio = False

    video = db_session.query(models.Video).filter_by(id=video_id).one_or_none()

    duration = float(streaminfo['format']['duration'])
    for stream in streaminfo['streams']:
        if stream['codec_type'] == 'video':
            vcodec = stream['codec_name']
            vwidth = stream['width']
            vheight = stream['height']
            framerate = stream['r_frame_rate']
            video_streamidx = stream['index']
        if stream['codec_type'] == 'audio':
            has_audio = True
            if audio_streamidx == -1 and stream['tags']['language'] == 'und':
                audio_streamidx = stream['index']
                audio_codec = stream['codec_name']
            if stream['tags']['language'] == 'eng':
                audio_streamidx = stream['index']
                audio_codec = stream['codec_name']

    if video_streamidx == -1:
        video_streamidx = 0
    if audio_streamidx == -1 and has_audio:
        audio_streamidx = 1

    try:
        framerate = round(float(framerate))
    except ValueError:
        x, y = framerate.split("/")
        framerate = round(int(x) / int(y))

    dash_size = 4
    keyint = framerate
    if vwidth > 1920:
        vheight = int(vheight / (vwidth / 1920))
        vwidth = 1920

    audio_formats = []
    if has_audio:
        audio_formats = [{
            'rate': '64k',
            'channels': '1'
        }, {
            'rate': '128k',
            'channels': '2'
        }, {
            'rate': '196k',
            'channels': '2'
        }]

    video_profiles = [
        {
            'profile': 'main',
            'preset': 'veryslow',
            'crf': '22',
            'maxrate': '600k',
            'bufsize': '800k',
            'width': 480
        },
        {
            'profile': 'main',
            'preset': 'slow',
            'crf': '22',
            'maxrate': '900k',
            'bufsize': '1200k',
            'width': 640
        },
        {
            'profile': 'high',
            'preset': 'slow',
            'crf': '22',
            'maxrate': '1200k',
            'bufsize': '1500k',
            'width': 960
        },
        {
            'profile': 'high',
            'preset': 'slow',
            'crf': '21',
            'maxrate': '2000k',
            'bufsize': '4000k',
            'width': 1280
        },
        {
            'profile': 'high',
            'preset': 'slow',
            'crf': '21',
            'maxrate': '4500k',
            'bufsize': '8000k',
            'width': 1920
        },
    ]

    video_formats = [{
        'profile': 'baseline',
        'preset': 'veryslow',
        'crf': '22',
        'maxrate': '200k',
        'bufsize': '300k',
        'width': 320
    }, {
        'profile': 'baseline',
        'preset': 'veryslow',
        'crf': '22',
        'maxrate': '400k',
        'bufsize': '500k',
        'width': 320
    }]

    sizes = [1, 1.5, 2, 3]
    for size in sizes:
        this_width = int(vwidth / size) + (int(vwidth / size) % 2)
        if this_width < video_profiles[0]['width']:
            next

        this_profile = None
        for idx in range(len(video_profiles)):
            if this_width == video_profiles[idx]['width']:
                this_profile = video_profiles[idx].copy()
                break

            if this_width > video_profiles[idx][
                    'width'] and this_width < video_profiles[idx + 1]['width']:
                this_profile = video_profiles[idx + 1].copy()
                this_profile['width'] = this_width
                break

        if this_profile:
            video_formats.append(this_profile)

    print(video_formats)

    tmpdir = tempfile.mkdtemp()
    socketfile = os.path.join(tmpdir, 'progress')
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.bind(socketfile)
    sock.listen(1)

    transcode_command = [
        'ffmpeg', '-y', '-nostdin', '-i', f'{tmpfile}', '-progress',
        f'unix://{socketfile}', '-loglevel', '24'
    ]
    dash_command = [
        'MP4Box', '-dash', f'{dash_size * 1000}', '-rap', '-frag-rap',
        '-min-buffer', '16000', '-profile', 'dashavc264:onDemand',
        '-mpd-title', video.title, '-out', master_playlist
    ]
    tmpfiles = []
    for num, f in enumerate(video_formats):
        stream = num
        filename = f'{outdir}/video_{f["width"]}_{f["maxrate"]}.mp4'
        transcode_command.extend([
            '-map', f'0:{video_streamidx}', f'-c:v', 'libx264', '-x264-params',
            f'no-scenecut', f'-profile:v', f['profile'], '-preset:v',
            f["preset"], '-tune:v', video.tune, '-keyint_min', f'{keyint}',
            '-g', f'{keyint}', '-sc_threshold', '0', '-bf', '1', '-b_strategy',
            '0', f'-crf', f['crf'], f'-maxrate', f'{f["maxrate"]}',
            f'-bufsize', f'{f["bufsize"]}', f'-filter',
            f'scale={f["width"]}:-2', '-map_chapters', '-1', filename
        ])
        dash_command.append(filename)
        tmpfiles.append(filename)

    for num, f in enumerate(audio_formats):
        stream = num
        filename = f'{outdir}/audio_{f["rate"]}.mp4'
        transcode_command.extend([
            '-map', f'0:{audio_streamidx}', f'-c:a', 'aac', f'-b:a', f['rate'],
            f'-ac', f['channels'], '-map_chapters', '-1', filename
        ])
        dash_command.append(filename)
        tmpfiles.append(filename)

    video.encoding_status = 'encoding'
    db_session.commit()

    ffmpeg = multiprocessing.Process(target=run_ffmpeg,
                                     args=(transcode_command,
                                           f'{tmpfile}.log'))
    ffmpeg.start()
    connection, client_address = sock.accept()
    percentage = 0
    speed = 0

    try:
        while True:
            data = connection.recv(1024)
            if data:
                string = data.decode('utf-8')
                for line in string.splitlines():
                    if line.startswith('out_time_ms'):
                        progress = int(line.split('=')[1]) / 1000000
                        percentage = (progress / duration) * 100
                        percentage = min(percentage, 100)
                    if line.startswith('speed'):
                        speed = float(line.split('=')[1].strip().split('x')[0])

                video.encoding_progress = percentage
                video.encoding_speed = speed
                db_session.commit()
            else:
                break

    finally:
        ffmpeg.terminate()
        connection.close()
        shutil.rmtree(tmpdir, ignore_errors=True)

        if percentage < 100:
            video.status = 'error'
            db_session.commit()

    try:
        print("Reencoded file")
        print(f'Executing: {" ".join(dash_command)}')
        output = subprocess.check_call(dash_command, stderr=subprocess.STDOUT)
        print("DASHed file")

        status = 'ready'

    except Exception as e:
        print(output)
        print(e)

    for f in tmpfiles:
        os.unlink(f)

    if celery.conf.get('STORAGE_BACKEND') == "S3":
        print("Uploading to S3")

        nthreads = celery.conf.get('S3_UPLOAD_THREADS')
        g = glob.glob(f"{outdir}/*")
        splits = numpy.array_split(g, nthreads)
        threads = list()

        for index in range(nthreads):
            x = threading.Thread(target=s3_upload,
                                 args=(splits[index].copy(), ))
            threads.append(x)
            x.start()

        for index, thread in enumerate(threads):
            thread.join()

        shutil.rmtree(outdir, ignore_errors=True)
        print("Done uploading")

    video.playlist = f'{video_id}/playlist.mpd'
    video.width = vwidth
    video.height = vheight
    video.duration = duration
    video.encoding_status = status
    db_session.commit()
示例#22
0
    def post(self, video_id):
        owner_id = request.cookies.get(app.config['COOKIE_OWNER_ID'])
        video = db_session.query(models.Video).filter_by(
            owner=owner_id, id=video_id).one_or_none()

        if not video:
            return {'message': 'Video not found'}, 403

        resumableTotalChunks = request.form.get('resumableTotalChunks',
                                                type=int)
        resumableChunkNumber = request.form.get('resumableChunkNumber',
                                                default=1,
                                                type=int)
        resumableIdentifier = request.form.get('resumableIdentifier',
                                               default='error',
                                               type=str)
        resumableFilename = request.form.get('resumableFilename',
                                             default='error',
                                             type=str)
        resumableTotalSize = request.form.get('resumableTotalSize',
                                              default=0,
                                              type=int)
        resumableChunkSize = request.form.get('resumableChunkSize',
                                              default=0,
                                              type=int)

        if not resumableIdentifier or not resumableChunkNumber or not resumableTotalSize or not resumableChunkSize:
            return {'message': 'Parameter error'}, 500

        target_file_name = target_name(video.id)
        chunk_data = request.files['file']

        if video.status in ['file-waiting', 'file-uploaded', 'ready', 'error']:
            video.status = 'file-uploading'
            video.upload_identifier = resumableIdentifier
            video.orig_file_name = resumableFilename
            video.orig_file = target_file_name.name
            db_session.commit()

        if video.upload_identifier != resumableIdentifier:
            return {'message': 'Different upload already in progress'}, 409

        try:
            if target_file_name.stat(
            ).st_size != resumableTotalSize or video.orig_file_name != resumableFilename:
                rm_f(target_file_name)
        except FileNotFoundError:
            pass

        if not target_file_name.exists():
            target_file = open(target_file_name, "wb")
            target_file.truncate(resumableTotalSize)
            target_file.close()

        upload_complete = False

        with open(target_file_name, "r+b") as target_file:
            offset = (resumableChunkNumber - 1) * resumableChunkSize
            target_file.seek(offset, os.SEEK_SET)
            target_file.write(chunk_data.read())

            fh = target_file.fileno()

            if os.lseek(fh, 0, os.SEEK_HOLE) == resumableTotalSize:
                upload_complete = True

            os.fsync(fh)

            last_chunk_offset = resumableTotalChunks * resumableChunkSize
            if resumableTotalSize >= resumableChunkSize:
                if (not is_hole(fh, resumableChunkSize - 1)
                        and resumableChunkNumber == resumableTotalChunks) or (
                            not is_hole(fh, resumableTotalSize - 1)
                            and resumableChunkNumber == 1):
                    update_video_metadata(video, target_file_name)

        if upload_complete:
            if not is_video_file(target_file_name):
                video.status = 'error'
                video.status_message = 'File uploaded was not a video file. Please use a different file.'
                db_session.commit()
                return {'message': video.status_message}, 501

            update_video_metadata(video, target_file_name)

            video.status = 'file-uploaded'
            video.encoding_progress = 0
            for encoded_file in video.encoded_files:
                rm_f(
                    os.path.join(app.config['MOVIE_PATH'], video.id,
                                 encoded_file.encoded_file_name))
                db_session.delete(encoded_file)
            db_session.commit()
示例#23
0
def resumable_post(video_id):
    video = db_session.query(models.Video).filter_by(
        owner=owner_id, id=video_id).one_or_none()
    if not video:
        return abort(403, "Video not found")

    resumableTotalChunks = request.form.get('resumableTotalChunks', type=int)
    resumableChunkNumber = request.form.get('resumableChunkNumber',
                                            default=1,
                                            type=int)
    resumableIdentfier = request.form.get('resumableIdentifier',
                                          default='error',
                                          type=str)

    # get the chunk data
    chunk_data = request.files['file']

    # make our temp directory
    temp_dir = os.path.join(app.config['MOVIE_PATH'], video_id, 'tmp',
                            resumableIdentfier)
    if not os.path.isdir(temp_dir):
        os.makedirs(temp_dir)

    # save the chunk data
    chunk_name = get_chunk_name('orig', resumableChunkNumber)
    chunk_file = os.path.join(temp_dir, chunk_name)
    chunk_data.save(chunk_file)
    app.logger.debug('Saved chunk: %s', chunk_file)

    # check if the upload is complete
    chunk_paths = [
        os.path.join(temp_dir, get_chunk_name('orig', x))
        for x in range(1, resumableTotalChunks + 1)
    ]
    upload_complete = all([os.path.exists(p) for p in chunk_paths])

    # combine all the chunks to create the final file
    if upload_complete:
        target_file_name = os.path.join(app.config['MOVIE_PATH'],
                                        f'{video_id}_orig')
        rm_f(target_file_name)
        with open(target_file_name, "ab") as target_file:
            for p in chunk_paths:
                stored_chunk_file_name = p
                stored_chunk_file = open(stored_chunk_file_name, 'rb')
                target_file.write(stored_chunk_file.read())
                stored_chunk_file.close()
                os.unlink(stored_chunk_file_name)
        target_file.close()
        os.rmdir(temp_dir)
        app.logger.debug('File saved to: %s', target_file_name)

        cmd = f'ffprobe -v quiet -show_streams -show_format -print_format json {target_file_name}'
        output = os.popen(cmd).read()
        output = json.loads(output)
        print(output)

        if output == {}:
            print("Not a video file")
            os.unlink(target_file_name)
            return make_response(
                jsonify({"message": "File is not a video file"}), 400)

        vcodec = ""
        for stream in output['streams']:
            if stream['codec_type'] == 'video':
                vcodec = stream['codec_name']

        if vcodec == "":
            os.unlink(target_file_name)
            return make_response(
                jsonify({"message": "File is not a video file"}), 400)

        tasks.transcode.delay(target_file_name, output, video_id)

    return 'OK'