예제 #1
0
def datang_create_video():
    """创建视频 (POST&LOGIN)

    :uri: /datang/videos/new-video
    :param game_id: 视频所属游戏id
    :param user_id: 用户ID
    :param title: 视频标题
    :param duration: 视频时长
    :param ratio: 视频尺寸
    :returns: object
    """
    user_id = request.values['user_id']
    game_id = request.values['game_id']
    video = DaTangVideo.init()
    video.author = user_id
    video.game = game_id
    video.title = request.values['title']

    if not Guard.verify_sig(request.values.to_dict()):
        return error.AuthFailed

    # 敏感词检查
    if Spam.filter_words(video.title, 'video'):
        return error.InvalidContent
    try:
        duration = int(request.values['duration'])
    except:
        return error.InvalidArguments

    video.duration = duration
    video.ratio = request.values['ratio']
    # 设置为文件上传状态, 文件上传成功之后更改为上线状态
    video.status = const.UPLOADING
    vid = video.create_model()
    return DaTangVideo.get_one(vid, check_online=False).format()
예제 #2
0
def datang_user_videos(uid):
    """获取用户创建的视频 (GET)

    :uri: /datang/users/<string:uid>/videos
    :params game_id: 游戏id
    :param maxs: 最后时间, 0代表当前时间, 无此参数按page来分页
    :param page: 页码(数据可能有重复, 建议按照maxs分页)
    :param nbr: 每页数量
    :returns: {'videos': list, 'end_page': bool, 'maxs': timestamp}
    """
    params = request.values
    maxs = params.get('maxs', None)
    maxs = time.time() if maxs is not None and int(float(maxs)) == 0 else maxs and float(maxs)
    page = int(params.get('page', 1))
    pagesize = int(params.get('nbr', 10))
    gid = params.get('game_id', None)

    videos = list()
    vids = list()
    while len(videos) < pagesize:
        vids = DaTangVideo.user_game_video_ids(uid, gid, page, pagesize, maxs)
        videos.extend([v.format() for v in DaTangVideo.get_list(vids)])

        # 如果按照maxs分页, 不足pagesize个记录则继续查询
        if maxs is not None:
            obj = DaTangVideo.get_one(vids[-1], check_online=False) if vids else None
            maxs = obj.create_at if obj else 1000
            if len(vids) < pagesize:
                break
        else:
            break

    return {'videos': videos, 'end_page': len(vids) != pagesize, 'maxs': maxs}
예제 #3
0
def datang_update_video(vid):
    """修改视频 (POST)

    :uri: /datang/videos/<string:vid>/update-video
    :param cover: 背景相对路径
    :param url: 视频相对路径
    :param upload_sig: 验证串
    :return: {'url': string}
    """
    cover = request.values.get('cover')
    url = request.values.get('url')
    valid_sig = request.values.get('upload_sig')
    md5 = hashlib.md5(vid)
    secret = '&%s' % ('29eb78ff3c8f20fe')
    md5.update(secret)
    if valid_sig != md5.hexdigest() or not cover or not url:
        return error.InvalidArguments

    video = DaTangVideo.get_one(vid, check_online=False)
    if not video:
        return error.VideoNotExist

    data = {'cover': cover, 'url': url, 'status': const.ONLINE}
    video = video.update_model({"$set": data})
    return {'video': video.format()}
예제 #4
0
def datang_game_popular_videos(gid):
    """获取游戏人气视频 (GET)

    :uri: /datang/games/<string:gid>/videos
    :param page: 页码
    :param nbr: 每页数量
    :returns: {'videos': list, 'end_page': bool}
    """
    params = request.values
    page = int(params.get('page', 1))
    pagesize = int(params.get('nbr', 10))

    videos = list()
    vids = DaTangVideo.game_hotvideo_ids(gid, page, pagesize)
    videos.extend([v.format() for v in DaTangVideo.get_list(vids)])
    return {'videos': videos, 'end_page': len(vids) != pagesize}
예제 #5
0
def datang_get_video(vid):
    """获取视频详细信息 (GET)

    :uri: /datang/videos/<string:vid>
    :returns: object
    """
    video = DaTangVideo.get_one(vid, check_online=False)
    if not video:
        return error.VideoNotExist

    return video.format()
예제 #6
0
def datang_upload_large_file():
    """大文件上传(POST&LOGIN)

    :uri: /datang/upload/upload-large-file
    :param type: 类型(videos.cover, videos.url)
    :param target_id: 对象id
    :param size: 文件大小
    :param ext: 文件后缀
    :returns: {'file_id': string, 'url': string}
    """
    _type = request.form.get("type", None)
    target_id = request.form.get("target_id", None)
    size = request.form.get("size", type=int)
    ext = request.form.get("ext")
    if _type not in {"videos.cover", "videos.url"}:
        return error.InvalidArguments

    if not Guard.verify_sig(request.form.to_dict()):
        return error.AuthFailed

    if not size or size <= 0:
        return error.InvalidArguments

    video = DaTangVideo.get_one(str(target_id), check_online=False)
    if not video:
        return error.VideoNotExist

    file_id = os.urandom(12).encode("hex")
    # 上传文件
    tmp_dir = os.path.join(app.config.get("STATIC_BASE"), "temp")
    file_path = os.path.join(tmp_dir, "l-%s.%s" % (file_id, ext))
    meta = dict(request.form.to_dict())
    meta['size'] = int(meta['size'])
    meta["file_id"] = file_id
    meta['path'] = file_path
    meta['user_id'] = video.author
    meta['ranges'] = list()
    try:
        _set_upload_file_meta(file_id, meta)
    except:
        return error.RedisFailed

    with open(file_path, "wb") as f:
        f.truncate(size)  # Pre-alloc file to get better performance on some fs.
    return {"file_id": file_id, "url": url_for("datang_upload_put_file", file_id=file_id)}
예제 #7
0
def datang_play_video(vid):
    """播放视频 (GET)

    :uri: /datang/videos/<string:vid>/play
    :returns: redirect(real_url)
    """
    start = int(time.time() * 1000)
    video = DaTangVideo.get_one(vid)
    if not video:
        result = {
            'status': error.VideoNotExist.errno,
            'errmsg': error.VideoNotExist.errmsg,
            'data': {},
            'time': int(time.time() * 1000) - start,
        }
        return jsonify(result)

    video.update_model({'$inc': {'vv': 1}})
    return redirect(video.real_url())
예제 #8
0
def datang_delete_video(vid):
    """删除视频 (POST&LOGIN)

    :uri: /datang/videos/<string:vid>/delete
    :param user_id: 大唐用户ID
    :returns: {}
    """
    user_id = request.values.get('user_id')

    if not Guard.verify_sig(request.values.to_dict()):
        return error.AuthFailed

    video = DaTangVideo.get_one(vid, check_online=False)
    if not video:
        return error.VideoNotExist

    if user_id != str(video.author):
        return error.AuthFailed

    video.delete_model()
    return {}
예제 #9
0
def datang_upload_small_file():
    """文件上传(POST&LOGIN)

    :uri: /datang/upload/upload-small-file
    :param type: 类型(videos.cover, videos.url)
    :param target_id: 对象id
    :param file: 上传文件
    :returns: {'target_id': string, 'type': string, 'url': string}
    """
    _type = request.form.get("type", None)
    target_id = request.form.get("target_id", None)
    if _type not in {"videos.cover", "videos.url"}:
        return error.InvalidArguments

    if not Guard.verify_sig(request.form.to_dict()):
        return error.AuthFailed

    video = DaTangVideo.get_one(str(target_id), check_online=False)
    if not video:
        return error.VideoNotExist

    # 上传文件
    _path = 'videos'
    _file = Media(app.config.get("STATIC_BASE"), _path, request.files['file'])
    try:
        url = _file.upload_file()
    except:
        return error.UploadFailed
    # 更新对象
    obj, attr = _type.split(".")
    data = {attr: url}
    if attr == 'url':
        data['status'] = const.ONLINE

    video.update_model({"$set": data})
    abs_url = urljoin(app.config.get('STATIC_URL'), url)
    return {'target_id': target_id, 'type': _type, 'url': abs_url}
예제 #10
0
def datang_upload_put_file(file_id):
    """大文件断点上传(PUT&LOGIN)

    :uri: /datang/upload/<file_id>
    :header Range: 片段信息(bytes=offset-length)
    :header Content-Type: application/octet-stream
    :returns: {'size': int, 'total': tuple, 'ranges': list, 'complete': bool, 'url': url}
    """
    meta = _get_upload_file_meta(file_id)
    if not os.path.exists(meta['path']):
        return error.UploadFailed('临时文件不存在')

    new_range = None
    start_bytes = 0
    # 'Range: bytes=offset-length'
    if 'Range' in request.headers:
        range_str = request.headers['Range']
        start_bytes = int(range_str.split('=')[1].split('-')[0])
        if start_bytes < 0 or start_bytes >= meta['size']:
            return error.UploadFailed('上传Range数据有问题')

    with open(meta['path'], 'r+') as f:
        f.seek(start_bytes)
        f.write(request.data)
        new_range = [start_bytes, len(request.data)]

    url = None
    # 处理多线程问题, 进行上锁
    key = 'lock:upload:%s' % (file_id)
    while Redis.get(key):
        time.sleep(0.1)

    with util.Lockit(Redis, key) as locked:
        if locked:
            return error.RedisFailed
        meta = _get_upload_file_meta(file_id)
        file_range = meta['ranges']
        file_range.append(new_range)
        file_range.sort()
        meta['ranges'] = reduce(_range_merge, file_range, [[0, 0]])
        try:
            _set_upload_file_meta(file_id, meta)
        except:
            return error.RedisFailed

    total = reduce(lambda x, y: (0, x[1] + y[1]), meta['ranges'], [0, 0])
    complete = False
    if len(meta['ranges']) == 1 and meta['ranges'][0][1] == meta['size']:
        _path = 'videos' if meta['type'] == 'videos.url' else 'images'
        _file = Media(app.config.get("STATIC_BASE"), _path, None)
        try:
            url = _file.upload_large_file(meta['path'], None, '.%s' % meta['ext'])
        except:
            return error.UploadFailed
        # 更新对象
        obj, attr = meta['type'].split(".")
        data = {attr: url}
        if attr == 'url':
            data['status'] = const.ONLINE
        model = DaTangVideo.get_one(meta['target_id'], check_online=False)

        model.update_model({"$set": data})
        complete = True

    abs_url = urljoin(app.config.get('STATIC_URL'), url) if url else None
    return {'size': len(request.data), 'total': total, 'url': abs_url,
            'ranges': meta['ranges'], 'complete': complete}