Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修改VideoModel #212

Merged
merged 23 commits into from
Jan 22, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
格式化videomanager
putianyi889 committed Jan 20, 2025
commit 882e22196002e12a472ad524a6f977d86afa5474
48 changes: 24 additions & 24 deletions back_end/saolei/videomanager/models.py
Original file line number Diff line number Diff line change
@@ -2,20 +2,21 @@
from django.db import models
from .fields import RestrictedFileField
from userprofile.models import UserProfile
from config.global_settings import *
from config.global_settings import DefaultRankingScores
from django_redis import get_redis_connection
cache = get_redis_connection("saolei_website")
import json
from utils import ComplexEncoder
from config.text_choices import MS_TextChoices
from config.global_settings import MaxSizes
cache = get_redis_connection("saolei_website")


class ExpandVideoModel(models.Model):
# video = models.OneToOneField(VideoModel, on_delete=models.CASCADE)
identifier = models.CharField(max_length=MaxSizes.identifier)
stnb = models.FloatField()
rqp = models.FloatField()


# 其他类:checksum_ok, mode

@@ -43,7 +44,7 @@ class ExpandVideoModel(models.Model):
# max_upload_size=5242880,)

def divideByTimeExpression(expr: models.Expression):
return models.Case(models.When(timems=0,then=models.Value(0.0)), default=expr / models.F('timems') * models.Value(1000), output_field = models.FloatField())
return models.Case(models.When(timems=0, then=models.Value(0.0)), default=expr / models.F('timems') * models.Value(1000), output_field=models.FloatField())


# 基本的录像模型,最小限度展示录像信息
@@ -69,41 +70,41 @@ class VideoModel(models.Model):
mode = models.CharField(
max_length=MaxSizes.gamemode, choices=MS_TextChoices.Mode.choices, default=MS_TextChoices.Mode.STD)
# 0.000-999.999
timems = models.PositiveIntegerField(default=DefaultRankingScores["timems"]) # 整数形式存储的毫秒数。
timems = models.PositiveIntegerField(default=DefaultRankingScores["timems"]) # 整数形式存储的毫秒数。
# 0-32767
bv = models.PositiveSmallIntegerField(null=True)
bvs = models.GeneratedField(expression = models.Case(models.When(timems=0,then=models.Value(0.0)), default=models.F('bv') / models.F('timems') * models.Value(1000), output_field = models.FloatField()), output_field = models.FloatField(), db_persist = True)
bvs = models.GeneratedField(expression=models.Case(models.When(timems=0, then=models.Value(0.0)), default=models.F('bv') / models.F('timems') * models.Value(1000), output_field=models.FloatField()), output_field=models.FloatField(), db_persist=True)

left = models.PositiveSmallIntegerField(null=True)
right = models.PositiveSmallIntegerField(null=True)
double = models.PositiveSmallIntegerField(null=True)
cl = models.GeneratedField(expression = models.F('left') + models.F('right') + models.F('double'), output_field = models.PositiveSmallIntegerField(), db_persist = True)
cl = models.GeneratedField(expression=models.F('left') + models.F('right') + models.F('double'), output_field=models.PositiveSmallIntegerField(), db_persist=True)

left_ce = models.PositiveSmallIntegerField(null=True)
right_ce = models.PositiveSmallIntegerField(null=True)
double_ce = models.PositiveSmallIntegerField(null=True)
ce = models.GeneratedField(expression = models.F('left_ce') + models.F('right_ce') + models.F('double_ce'), output_field = models.PositiveSmallIntegerField(), db_persist = True)
ce = models.GeneratedField(expression=models.F('left_ce') + models.F('right_ce') + models.F('double_ce'), output_field=models.PositiveSmallIntegerField(), db_persist=True)

# 需要处理除零错误
left_s = models.GeneratedField(expression = divideByTimeExpression(models.F('left')), output_field = models.FloatField(), db_persist = True)
right_s = models.GeneratedField(expression = divideByTimeExpression(models.F('right')), output_field = models.FloatField(), db_persist = True)
double_s = models.GeneratedField(expression = divideByTimeExpression(models.F('double')), output_field = models.FloatField(), db_persist = True)
cl_s = models.GeneratedField(expression = divideByTimeExpression(models.F('cl')), output_field = models.FloatField(), db_persist = True)
left_s = models.GeneratedField(expression=divideByTimeExpression(models.F('left')), output_field=models.FloatField(), db_persist=True)
right_s = models.GeneratedField(expression=divideByTimeExpression(models.F('right')), output_field=models.FloatField(), db_persist=True)
double_s = models.GeneratedField(expression=divideByTimeExpression(models.F('double')), output_field=models.FloatField(), db_persist=True)
cl_s = models.GeneratedField(expression=divideByTimeExpression(models.F('cl')), output_field=models.FloatField(), db_persist=True)

left_ces = models.GeneratedField(expression = divideByTimeExpression(models.F('left_ce')), output_field = models.FloatField(), db_persist = True)
right_ces = models.GeneratedField(expression = divideByTimeExpression(models.F('right_ce')), output_field = models.FloatField(), db_persist = True)
double_ces = models.GeneratedField(expression = divideByTimeExpression(models.F('double_ce')), output_field = models.FloatField(), db_persist = True)
ce_s = models.GeneratedField(expression = divideByTimeExpression(models.F('ce')), output_field = models.FloatField(), db_persist = True)
left_ces = models.GeneratedField(expression=divideByTimeExpression(models.F('left_ce')), output_field=models.FloatField(), db_persist=True)
right_ces = models.GeneratedField(expression=divideByTimeExpression(models.F('right_ce')), output_field=models.FloatField(), db_persist=True)
double_ces = models.GeneratedField(expression=divideByTimeExpression(models.F('double_ce')), output_field=models.FloatField(), db_persist=True)
ce_s = models.GeneratedField(expression=divideByTimeExpression(models.F('ce')), output_field=models.FloatField(), db_persist=True)

path = models.FloatField(null=True)
flag = models.PositiveSmallIntegerField(null=True)
op = models.PositiveSmallIntegerField(null=True)
isl = models.PositiveSmallIntegerField(null=True)

flag_s = models.GeneratedField(expression = divideByTimeExpression(models.F('flag')), output_field = models.FloatField(), db_persist = True)
ioe = models.GeneratedField(expression = models.F('bv') / models.F('cl'), output_field = models.FloatField(), db_persist = True)
thrp = models.GeneratedField(expression = models.F('bv') / models.F('ce'), output_field = models.FloatField(), db_persist = True)
corr = models.GeneratedField(expression = models.F('ce') / models.F('cl'), output_field = models.FloatField(), db_persist = True)
flag_s = models.GeneratedField(expression=divideByTimeExpression(models.F('flag')), output_field=models.FloatField(), db_persist=True)
ioe = models.GeneratedField(expression=models.F('bv') / models.F('cl'), output_field=models.FloatField(), db_persist=True)
thrp = models.GeneratedField(expression=models.F('bv') / models.F('ce'), output_field=models.FloatField(), db_persist=True)
corr = models.GeneratedField(expression=models.F('ce') / models.F('cl'), output_field=models.FloatField(), db_persist=True)

cell0 = models.PositiveSmallIntegerField(null=True)
cell1 = models.PositiveSmallIntegerField(null=True)
@@ -122,10 +123,10 @@ def __getattr__(self, name):
elif name == "ioe":
return self.video.ioe
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

def __str__(self):
return f'level: {self.level}, timems: {self.timems}, 3BV: {self.bv}'

class Meta:
indexes = [
models.Index(fields=['level'], name='level_idx'),
@@ -149,7 +150,6 @@ def push_redis(self, name: str):
"bv": self.bv,
"bvs": self.bvs,
"identifier": self.video.identifier}, cls=ComplexEncoder))

def pop_redis(self, name: str):
cache.hdel(name, self.id)

8 changes: 4 additions & 4 deletions back_end/saolei/videomanager/tests.py
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ def test_zero_time(self):
'cell3': 0, 'cell4': 0, 'cell5': 0,
'cell6': 0, 'cell7': 0, 'cell8': 0,

'bvs': 0, 'cl': 1, 'ce': 1,
'bvs': 0, 'cl': 1, 'ce': 1,
'cl_s': 0, 'ce_s': 0, 'flag_s': 0,
'ioe': 1, 'thrp': 1, 'corr': 1,
}
@@ -43,7 +43,7 @@ def test_refresh(self):
expandvideo = ExpandVideoModel.objects.create(identifier='test', stnb=0, rqp=0)
video = VideoModel.objects.create(player=self.user, file=ContentFile(response.content, name='Exp_FL_35.09_3BV=132_3BVs=3.76_Pu Tian Yi(Hu Bei).avf'), video=expandvideo, state='a')
refresh_video(video)

video = VideoModel.objects.get(id=video.id)

expected_values = {
@@ -57,7 +57,7 @@ def test_refresh(self):
'cell3': 45, 'cell4': 24, 'cell5': 1,
'cell6': 0, 'cell7': 0, 'cell8': 0,
}

self.multiple_values_test(video, expected_values)

expected_extended_values = {
@@ -66,4 +66,4 @@ def test_refresh(self):
'rqp': 9.328091666666667,
}

self.multiple_values_test(video.video, expected_extended_values)
self.multiple_values_test(video.video, expected_extended_values)
11 changes: 5 additions & 6 deletions back_end/saolei/videomanager/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.urls import include, path
from django.urls import path

from . import views
app_name = 'video'
@@ -14,10 +14,9 @@
path('news_queue/', views.news_queue, name='news_queue'),
# path('approve/', views.approve, name='approve'),
# path('freeze/', views.freeze, name='freeze'),
path('get/',views.get_videoModel),
path('set/',views.set_videoModel),
path('update/',views.update_videoModel),
path('get/', views.get_videoModel),
path('set/', views.set_videoModel),
path('update/', views.update_videoModel),
path('refresh_all/', views.refresh_all_videoModel),
# path('download/', views.video_download, name='download'),

]
]
75 changes: 39 additions & 36 deletions back_end/saolei/videomanager/view_utils.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import logging
logger = logging.getLogger('videomanager')
from .models import VideoModel, ExpandVideoModel
from django_redis import get_redis_connection
cache = get_redis_connection("saolei_website")
from userprofile.models import UserProfile
from msuser.models import UserMS
import json
from utils import ComplexEncoder
from config.global_settings import *
from config.global_settings import RankingGameStats, GameLevels, GameModes, DefaultRankingScores
from utils.cmp import isbetter
from django.db.models import F, ExpressionWrapper, DecimalField
from config.text_choices import MS_TextChoices
import ms_toollib as ms

logger = logging.getLogger('videomanager')
cache = get_redis_connection("saolei_website")

record_update_fields = []
for mode in GameModes:
for stat in RankingGameStats:
@@ -32,6 +32,7 @@
MS_TextChoices.State.OFFICIAL: 'newest_queue',
}


# 确定用户破某个纪录后,且对应模式、指标的三个级别全部有录像后,更新redis中的数据
def update_3_level_cache_record(realname: str, index: str, mode: str, ms_user: UserMS):
key = f"player_{index}_{mode}_{ms_user.id}"
@@ -40,18 +41,17 @@ def update_3_level_cache_record(realname: str, index: str, mode: str, ms_user: U
cache.hset(key, level, ms_user.getrecord(level, index, mode))
recordid = ms_user.getrecordID(level, index, mode)
cache.hset(key, f"{level}_id", "None" if recordid is None else recordid)
s = float(ms_user.getrecord("b", index, mode) + ms_user.getrecord("i", index, mode) +\
ms_user.getrecord("e", index, mode))
s = float(ms_user.getrecord("b", index, mode) + ms_user.getrecord("i", index, mode) + ms_user.getrecord("e", index, mode))
cache.hset(key, "sum", s)
cache.zadd(f"player_{index}_{mode}_ids", {ms_user.id: s})
cache.zadd(f"player_{index}_{mode}_ids", {ms_user.id: s})


# 确定用户破某个纪录后,更新redis破纪录的记录,显示在首页用
def update_news_queue(user: UserProfile, ms_user: UserMS, video: VideoModel, index: str, mode: str):
if ms_user.e_timems_std >= 60000 and (index != "timems" or video.level != "e"):
return
# print(f"{type(index)} {index}") # 调试用
value = f"{getattr(video, index)/1000:.3f}" if index == "timems" else f"{getattr(video, index):.3f}"
value = f"{getattr(video, index) / 1000:.3f}" if index == "timems" else f"{getattr(video, index):.3f}"
delta_number = getattr(video, index) - ms_user.getrecord(video.level, index, mode)
if index == "timems":
delta_number /= 1000
@@ -81,20 +81,21 @@ def checkRanking(userprof: UserProfile, user: UserMS, mode, statname):
return
update_3_level_cache_record(userprof.realname, statname, mode, user)


# 检查某录像是否打破个人纪录
def checkPB(video: VideoModel, user: UserMS, userprof: UserProfile, mode):
for statname in RankingGameStats:
stat = getattr(video, statname)
if stat != None and isbetter(statname, stat, user.getrecord(video.level, statname, mode)):
if stat is not None and isbetter(statname, stat, user.getrecord(video.level, statname, mode)):
update_news_queue(userprof, user, video, statname, mode)
user.setrecord(video.level, statname, mode, stat)
user.setrecordID(video.level, statname, mode, video.video.id)
checkRanking(userprof, user, mode, statname)


def update_personal_record(video: VideoModel):
if video.state != MS_TextChoices.State.OFFICIAL:
return
e_video = video.video
user = video.player
ms_user = user.userms

@@ -151,8 +152,9 @@ def update_personal_record_stock(user: UserProfile):
for v in videos:
update_personal_record(v)


# 上传的录像进入数据库后,更新用户的录像数目
def update_video_num(video: VideoModel, add = True):
def update_video_num(video: VideoModel, add=True):
userms = video.player.userms
# add = True:新增录像;add = False:删除录像
if video.mode == '00':
@@ -184,12 +186,11 @@ def update_video_num(video: VideoModel, add = True):
userms.video_num_limit = 800
if video.timems < 30000 and userms.video_num_limit < 1000:
userms.video_num_limit = 1000

userms.save(update_fields=["video_num_limit", "video_num_total", "video_num_beg", "video_num_int",
"video_num_exp", "video_num_std", "video_num_nf", "video_num_ng",
"video_num_dg"])

def update_state(video: VideoModel, state: MS_TextChoices.State, update_ranking = True):
userms.save(update_fields=["video_num_limit", "video_num_total", "video_num_beg", "video_num_int", "video_num_exp", "video_num_std", "video_num_nf", "video_num_ng", "video_num_dg"])


def update_state(video: VideoModel, state: MS_TextChoices.State, update_ranking=True):
prevstate = video.state
if prevstate == state:
return
@@ -202,50 +203,51 @@ def update_state(video: VideoModel, state: MS_TextChoices.State, update_ranking
update_personal_record(video)
elif update_ranking and prevstate == MS_TextChoices.State.OFFICIAL:
update_personal_record_stock(video)



def new_video(data, user):
e_video = ExpandVideoModel.objects.create(
identifier=data["identifier"],
cl_s=data["cl_s"],
stnb=data["stnb"],
rqp=data["rqp"],
rqp=data["rqp"],
ioe=data["ioe"],
thrp=data["thrp"],
thrp=data["thrp"],
corr=data["corr"],
ce_s=data["ce_s"],)
video = VideoModel.objects.create(
player=user,
file=data["file"],
player=user,
file=data["file"],
video=e_video,
state=["c", "b", "d", "a"][data['review_code']],
software=data["software"],
state=["c", "b", "d", "a"][data['review_code']],
software=data["software"],
level=data["level"],
mode=data["mode"] if data["mode"]!="00" else ("12" if data["flag"]==0 else "00"),
mode=data["mode"] if data["mode"] != "00" else ("12" if data["flag"] == 0 else "00"),

timems=data["timems"],
bv=data["bv"],
left=data["left"],
left=data["left"],
right=data["right"],
double=data["double"],
double=data["double"],
left_ce=data["left_ce"],
right_ce=data["right_ce"],
double_ce=data["double_ce"],
path=data["path"],
path=data["path"],
flag=data["flag"],
op=data["op"],
op=data["op"],
isl=data["isl"],
cell0=data["cell0"],
cell0=data["cell0"],
cell1=data["cell1"],
cell2=data["cell2"],
cell2=data["cell2"],
cell3=data["cell3"],
cell4=data["cell4"],
cell4=data["cell4"],
cell5=data["cell5"],
cell6=data["cell6"],
cell6=data["cell6"],
cell7=data["cell7"],
cell8=data["cell8"])

# 参考ms_toollib.is_valid的返回值
if data['review_code'] == 3: # 不确定
if data['review_code'] == 3: # 不确定
logger.info(f'用户 {user.username}#{user.id} 录像#{video.id} 机审失败')
video.push_redis("review_queue")
update_video_num(video)
@@ -256,12 +258,13 @@ def new_video(data, user):
elif data['review_code'] == 1:
logger.info(f'用户 {user.username}#{user.id} 录像#{video.id} 不合法')
video.push_redis("freeze_queue")
elif data['review_code'] == 0: # 合法
elif data['review_code'] == 0: # 合法
logger.info(f'用户 {user.username}#{user.id} 录像#{video.id} 机审成功')
video.push_redis("newest_queue")
update_personal_record(video)
update_video_num(video)


def refresh_video(video: VideoModel):
if video.file.path.endswith('.avf'):
v = ms.AvfVideo(video.file.path)
@@ -285,7 +288,7 @@ def refresh_video(video: VideoModel):
video.level = 'c'
else:
return

video.timems = v.rtime_ms
video.bv = v.bbbv

98 changes: 58 additions & 40 deletions back_end/saolei/videomanager/views.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
# -*- coding: utf-8 -*-
import logging
logger = logging.getLogger('videomanager')
from .forms import UploadVideoForm
from .models import VideoModel, ExpandVideoModel
from .view_utils import update_personal_record, update_personal_record_stock, video_all_fields, update_video_num, update_state, new_video, refresh_video
from userprofile.models import UserProfile
from django.http import HttpResponse, JsonResponse, FileResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotAllowed, HttpResponseNotFound
import json, urllib
from django.http import HttpResponse, JsonResponse, FileResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotFound
import json
import urllib
from utils import ComplexEncoder
from django.core.paginator import Paginator
from config.text_choices import MS_TextChoices
from django.db.models import Q
from django_redis import get_redis_connection
cache = get_redis_connection("saolei_website")
from django_ratelimit.decorators import ratelimit
from django.conf import settings
from identifier.utils import verify_identifier
from django.views.decorators.http import require_GET, require_POST
from userprofile.decorators import banned_blocked, staff_required, login_required_error
from config.text_choices import MS_TextChoices

logger = logging.getLogger('videomanager')
cache = get_redis_connection("saolei_website")


@require_POST
@login_required_error
@banned_blocked
@ratelimit(key='ip', rate='5/s')
def video_upload(request):
if request.user.userms.video_num_total >= request.user.userms.video_num_limit:
return HttpResponse(status = 402) # 录像仓库已满
return HttpResponse(status=402) # 录像仓库已满

video_form = UploadVideoForm(data=request.POST, files=request.FILES)
if not video_form.is_valid():
return HttpResponseBadRequest(video_form.errors)
data = video_form.cleaned_data
identifier = data["identifier"]
if not verify_identifier(identifier): # 标识不过审
if not verify_identifier(identifier): # 标识不过审
return JsonResponse({'type': 'error', 'object': 'identifier', 'category': 'censorship'})
if data['review_code'] == 0 and identifier not in request.user.userms.identifiers:
data['review_code'] = 2 # 标识不匹配
data['review_code'] = 2 # 标识不匹配

# 查重
collisions = list(VideoModel.objects.filter(timems=data["timems"], bv=data["bv"]).filter(path=data["path"]).filter(left=data["left"], right=data["right"],double=data["double"],op=data["op"], isl=data["isl"], video__identifier=data["identifier"]))
collisions = list(VideoModel.objects.filter(timems=data["timems"], bv=data["bv"]).filter(path=data["path"]).filter(left=data["left"], right=data["right"], double=data["double"], op=data["op"], isl=data["isl"], video__identifier=data["identifier"]))
if collisions:
return JsonResponse({'type': 'error', 'object': 'videomodel', 'category': 'conflict'})
new_video(data, request.user) # 表中添加数据
return JsonResponse({'type': 'error', 'object': 'videomodel', 'category': 'conflict'})
new_video(data, request.user) # 表中添加数据
return JsonResponse({'type': 'success', 'object': 'videomodel', 'category': 'upload'})


@@ -51,6 +54,7 @@ def get_software(request):
video = VideoModel.objects.get(id=request.GET["id"])
return JsonResponse({"msg": video.software})


# 给预览用的接口,区别是结尾是文件后缀
# 坑:如果做成必须登录才能下载,由于Django的某种特性,会重定向资源,
# 然而flop播放器不能处理此状态码,因此会请求到空文件,导致解码失败
@@ -62,33 +66,34 @@ def video_preview(request):
# video.file.name是相对路径(含upload_to),video.file.path是绝对路径
# print(settings.MEDIA_ROOT / "assets" / video.file.name)
file_path = settings.MEDIA_ROOT / video.file.name
response =FileResponse(open(file_path, 'rb'))
response['Content-Type']='application/octet-stream'
response = FileResponse(open(file_path, 'rb'))
response['Content-Type'] = 'application/octet-stream'
# response['Content-Disposition']=f'attachment;filename="{video.file.name.split("/")[2]}"'
file_name = video.file.name.split("/")[2]
file_name_uri = urllib.parse.quote(file_name)
response['Content-Disposition'] = f'attachment; filename="{file_name_uri}"'
response['Access-Control-Expose-Headers']='Content-Disposition'
response['Access-Control-Expose-Headers'] = 'Content-Disposition'
return response


# 给下载用的接口,区别是结尾没有文件后缀
# @login_required(login_url='/')
@ratelimit(key='ip', rate='20/m')
@require_GET
def video_download(request):
try:
video = VideoModel.objects.get(id=request.GET["id"])
response =FileResponse(open(video.file.path, 'rb'))
response['Content-Type']='application/octet-stream'
response['Content-Disposition']=f'attachment;filename="{video.file.name.split("/")[2]}"'
response = FileResponse(open(video.file.path, 'rb'))
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = f'attachment;filename="{video.file.name.split("/")[2]}"'
return response
except VideoModel.DoesNotExist:
return HttpResponseNotFound()


# 录像查询(无需登录)
# 按任何基础指标+难度+模式,排序,分页
# 每项的定义参见 front_end/src/views/VideoView.vue 的 request_videos 函数

@ratelimit(key='ip', rate='60/m')
@require_GET
def video_query(request):
@@ -105,15 +110,15 @@ def video_query(request):
orderby = (ob, "timems")
else:
orderby = (ob,)

if data["mode"] != "00":
filter = {"level": data["level"], "mode": data["mode"]}
videos = VideoModel.objects.filter(**filter)
else:
filter = {"level": data["level"]}
videos = VideoModel.objects.filter(Q(mode="00")|Q(mode="12")).filter(**filter)
videos = videos.filter(bv__range=(data["bmin"],data["bmax"]))
videos = VideoModel.objects.filter(Q(mode="00") | Q(mode="12")).filter(**filter)

videos = videos.filter(bv__range=(data["bmin"], data["bmax"]))

states = data.getlist("s[]")
if states:
@@ -147,14 +152,14 @@ def video_query_by_id(request):
return JsonResponse(list(videos), safe=False)



# 获取审查队列里的录像
# http://127.0.0.1:8000/video/review_queue
@require_GET
def review_queue(request):
review_video_ids = cache.hgetall("review_queue")
for key in list(review_video_ids.keys()):
review_video_ids.update({str(key, encoding="utf-8"): review_video_ids.pop(key)})
review_video_ids.update({
str(key, encoding="utf-8"): review_video_ids.pop(key)})
return JsonResponse(review_video_ids, encoder=ComplexEncoder)


@@ -164,27 +169,30 @@ def review_queue(request):
def newest_queue(request):
newest_queue_ids = cache.hgetall("newest_queue")
for key in list(newest_queue_ids.keys()):
newest_queue_ids.update({str(key, encoding="utf-8"): newest_queue_ids.pop(key)})
newest_queue_ids.update({
str(key, encoding="utf-8"): newest_queue_ids.pop(key)})
return JsonResponse(newest_queue_ids, encoder=ComplexEncoder)


# 获取谁破纪录的消息
# http://127.0.0.1:8000/video/news_queue
@require_GET
def news_queue(request):
news_queue = cache.lrange("news_queue", 0, -1)
return JsonResponse(news_queue, encoder=ComplexEncoder, safe=False)


# 获取全网被冻结的录像
# http://127.0.0.1:8000/video/freeze_queue
@require_GET
def freeze_queue(request):
freeze_queue_ids = cache.hgetall("freeze_queue")
for key in list(freeze_queue_ids.keys()):
freeze_queue_ids.update({str(key, encoding="utf-8"): freeze_queue_ids.pop(key)})
freeze_queue_ids.update({
str(key, encoding="utf-8"): freeze_queue_ids.pop(key)})
return JsonResponse(freeze_queue_ids, encoder=ComplexEncoder)



# 审核通过单个录像
# check_identifier 为 true 则检查是否要修改玩家标识列表,并在修改后扫描所有待审录像的标识
def approve_single(videoid, check_identifier=True):
@@ -208,6 +216,7 @@ def approve_single(videoid, check_identifier=True):
approve_identifier(video.player.id, identifier)
return True


# 审核通过所有特定用户特定标识的录像
def approve_identifier(userid, identifier):
user_identifier_list = cache.hgetall("review_queue")
@@ -231,6 +240,7 @@ def approve(request):
res.append(approve_single(_id))
return JsonResponse(res, safe=False)


# 【管理员】冻结队列里的录像,未审核或审核通过的录像可以冻结
# 两种用法,冻结指定的录像id,或冻结某用户的所有录像
# 冻结的录像七到14天后删除,用一个定时任务
@@ -241,15 +251,15 @@ def approve(request):
@staff_required
def freeze(request):
if ids := request.GET.get("ids"):
res = []
res = []
for id in ids:
if not (v := VideoModel.objects.filter(id=id).first()):
res.append("Null")
else:
update_state(v, MS_TextChoices.State.FROZEN)
logger.info(f'管理员 {request.user.username}#{request.user.id} 冻结录像#{id}')
return JsonResponse(res)
elif user_id := request.GET.get("user_id"):
elif user_id := request.GET.get("user_id"):
if not (user := UserProfile.objects.filter(id=user_id).first()):
return HttpResponseNotFound()
for v in VideoModel.objects.filter(player=user):
@@ -259,36 +269,43 @@ def freeze(request):
else:
return HttpResponseBadRequest()


# 管理员使用的操作接口,调用方式见前端的StaffView.vue
get_videoModel_fields = ["player", "player__realname", "upload_time", "state", "software", "level", "mode", "timems", "bv", "bvs"] # 可获取的域列表
get_videoModel_fields = ["player", "player__realname", "upload_time", "state", "software", "level", "mode", "timems", "bv", "bvs"] # 可获取的域列表
for name in [field.name for field in ExpandVideoModel._meta.get_fields()]:
get_videoModel_fields.append("video__" + name)


@require_GET
@staff_required
def get_videoModel(request):
if not (videolist := VideoModel.objects.filter(id=request.GET["id"]).values(*get_videoModel_fields)):
if not (videolist := VideoModel.objects.filter(id=request.GET["id"])
.values(*get_videoModel_fields)):
return HttpResponseNotFound()
return JsonResponse(videolist[0])

set_videoModel_fields = ["player", "upload_time", "state"] # 可修改的域列表


set_videoModel_fields = ["player", "upload_time", "state"] # 可修改的域列表


@require_POST
@staff_required
def set_videoModel(request):
videoid = request.POST.get("id")
video = VideoModel.objects.get(id=videoid)
user = video.player
if user.is_staff and user != request.user:
return HttpResponseForbidden() # 不能修改除自己以外管理员的信息
return HttpResponseForbidden() # 不能修改除自己以外管理员的信息
field = request.POST.get("field")
if field not in set_videoModel_fields:
return HttpResponseForbidden() # 只能修改特定的域
return HttpResponseForbidden() # 只能修改特定的域
value = request.POST.get("value")
logger.info(f'管理员 {request.user.username}#{request.user.id} 修改录像#{videoid}{field}{getattr(video, field)}{value}')
setattr(video, field, value)
video.save()
return HttpResponse()


@require_POST
@staff_required
def update_videoModel(request):
@@ -298,6 +315,7 @@ def update_videoModel(request):
refresh_video(video)
return HttpResponse()


@require_GET
def refresh_all_videoModel(request):
if not request.user.is_superuser:
@@ -307,4 +325,4 @@ def refresh_all_videoModel(request):
refresh_video(video)
except:
return JsonResponse({'type': 'error', 'value': video.id})
return JsonResponse({'type': 'success'})
return JsonResponse({'type': 'success'})