icdd-vsumm/static/js/index.js

194 lines
7.3 KiB
JavaScript

/**
* 当主页中的“选择视频”按钮被点击后, 执行此函数
*
* 1) 弹出一个文件选择框, 让用户选定一些本地文件
*/
function onSelectVideoButtonClicked() {
// 当用户选定了一些文件后, 函数 onUploadVideoChanged 将被执行.
$('#upload-video').click();
}
/**
* 当主页中的“选择视频”按钮被点击后, 且用户选定了一些文件时, 此函数将被调用.
*
* 1) 检查这些文件的格式. 目前可以处理的视频文件格式是*.mp4
* 2) 将按钮'select-video'隐藏
* 3) 将表格'status-table'显示
*
* 对于每个已选定的文件, 均执行以下异步流程:
*
* 1) 调用服务器的接口, 将文件上传到服务器
* 2) 将标题'caption'修改为 '正在处理{files.length}个文件, 请稍候查看结果'
* 3) 为表格'status-table'追加一行, 用于展示处理当前文件的状态与进度, 并提供用户可执行的操作
*
* @param {file} files 用户选择的文件列表.
*/
function onUploadVideoChanged(files) {
for (var index = 0; index < files.length; index++) {
var file = files[index];
if (file.type != 'video/mp4') {
errorModal('错误', `文件${file.name}的格式错误`);
return;
}
}
$('#select-video').hide();
$('#status-table').show();
$('#caption').html('正在处理' + files.length + '个文件');
$.each(files, function(index, file) {
uploadFile(index, file);
appendRowToStatusTable(index, file);
});
}
/**
* 当文件完成部分上传时, 此函数将被回调, 用于更新部分页面组件.
*
* 1) 将表格 status-table 中进度栏的进度信息修改为 '${percent}%'
*
* @param {index} index 文件的索引
* @param {number} percent 文件的上传进度
*/
function onFileUploadStepped(index, percent) {
prog = $(`#stat-prog-${index}`);
prog.css({'width': `${percent}%`});
prog.html(`${percent}%`);
}
/**
* 当文件上传成功后, 此函数将被回调, 用于开始进行特征提取, 同时更新部分界面组件.
*
* 1) 将表格 status-table 中状态栏的信息改为 '正在提取'
* 2) 将表格 status-table 中进度栏的进度信息重置为 '0%'
* 3) 调用服务器接口, 开始执行推理
*
* @param {number} index 文件的索引
* @param {File} file 文件对象
* @param {object} data 服务器响应数据
*/
function onFileUploadFinished(index, file, data) {
$(`#stat-label-${index}`).html('正在提取');
$(`#stat-prog-${index}`).css({'width': '0%'});
$(`#stat-prog-${index}`).html('0%');
}
/**
* 当文件上传失败后, 此函数将被回调, 用于更新部分界面组件.
*
* 1) 将表格 status-table 中的状态栏信息改为 '上传失败'.
* 2) 将表格 status-table 中进度栏的进度信息重置为 '0%'
* 3) 将表格 status-table 中操作栏的按钮修改为 danger, 并激活以查看失败原因.
*
* @param {number} index 文件的索引
* @param {File} file 文件对象
* @param {error} err 失败原因
*/
function onFileUploadFailed(index, file, err) {
$(`#stat-label-${index}`).html('<div class="text-danger">上传失败</div>');
$(`#stat-prog-${index}`).css({'width': '0%'});
$(`#stat-prog-${index}`).html('0%');
$(`#stat-button-${index}`).removeClass('btn-dark disabled');
$(`#stat-button-${index}`).addClass('btn-danger');
$(`#stat-button-${index}`).find('span').remove();
$(`#stat-button-${index}`).text('查看');
$(`#stat-button-${index}`).on('click', function() {
errorModal('错误', `文件${file.name}上传失败: ${err}`);
});
}
/**
* 上传指定的文件到服务器的接口.
*
* 此函数会回调 onFileUploadStepped 函数, 告知文件的上传进度.
*
* @param {index} index 文件的索引
* @param {file} file 文件对象
*/
function uploadFile(index, file) {
var formData = new FormData();
formData.append('file', file);
$.ajax({
url: 'http://127.0.0.1:8000/upload',
type: 'POST',
data: formData,
processData: false, // 不处理发送的数据
contentType: false, // 不设置内容类型
success: function(data) {
if (data.status != 200) {
//TODO: 添加错误处理
} else {
onFileUploadFinished(index, file, data);
}
},
error: function(xhr, status, error) {
if (xhr.status == 0) {
error = '连接到服务器失败!';
} else {
var errorAjax = `AJAX error: ${status} : ${error}`;
var errorResponseText = `ResponseText: ${xhr.responseText}`;
var errorStatusText = `StatusText: ${xhr.statusText}`;
error = `${errorAjax} + \n\n + ${errorResponseText} + \n\n + ${errorStatusText}`;
}
onFileUploadFailed(index, file, error);
},
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', function(event) {
if (event.lengthComputable) {
var percent = event.loaded / event.total;
percent = parseInt(percent * 100);
onFileUploadStepped(index, percent);
}
}, false);
return xhr;
},
});
}
/**
* 在结果窗口中播放服务器中编号为id的视频.
*
* @param {string} id 服务器视频id
*/
function playFile(index, file, id) {
$('#video-modal').find('.modal-title').text(`预览${file ? file.name : '此视频'}的关键镜头`);
$('#video-modal').find('video').attr('src', `http://127.0.0.1:8000/fetch/${id}`);
var player = new Plyr('video');
$('#video-modal').modal();
$('#video-modal').on('hidden.bs.modal', function(event) {
player.pause();
});
}
/**
* 向表格'status-table'中增加一行, 向用户展示上传文件的信息与当前状态, 并提供必要的操作.
*
* @param {number} index 正在处理的文件编号.
* @param {file} file 正在处理的文件对象.
* @note 在执行此函数时, 该文件对象可能正在异步上传.
*/
function appendRowToStatusTable(index, file) {
var fileNameHtml = `<td>${file.name}</td>`;
var fileTypeHtml = `<td>${file.type}</td>`;
var fileSizeHtml = `<td>${getReadableSize(file.size)}</td>`;
var fileStatHtml = `<td id='stat-label-${index}'>正在上传</td>`;
var fileProgHtml = `<td><div class='progress'><div id='stat-prog-${index}' class='progress-bar' style='width:0%'>0%</div></div></td>`;
var fileOptrHtml = `<td><button id='stat-button-${index}' type='button' class='btn btn-dark btn-sm disabled'><span class="spinner-border spinner-border-sm"></span></button></td>`;
$('#status-table').append(
'<tr>' + fileNameHtml + fileTypeHtml + fileSizeHtml + fileStatHtml + fileProgHtml + fileOptrHtml + '</tr>'
);
}
// 注册按钮点击事件处理函数
$(document).ready(function() {
$('#select-video').click(onSelectVideoButtonClicked);
});
// 注册文件选择事件处理函数
$(document).ready(function() {
$('#upload-video').change(function() {
var files = $(this).prop('files');
onUploadVideoChanged(files);
});
});