Skip to content

Commit

Permalink
Merge pull request #7 from BobH233/main
Browse files Browse the repository at this point in the history
WebUI 以及 Docker部署
  • Loading branch information
AuYang261 authored May 17, 2024
2 parents 6a10817 + 01d89ed commit 55fc1df
Show file tree
Hide file tree
Showing 9 changed files with 711 additions and 1 deletion.
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
__pycache__/
output/
old/
*.zip
*.exe
build/
dist/
*.spec
whisper_models/
release_*/
*.json
.idea
.DS_Store
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ dist/
whisper_models/
release_*/
*.json
.idea
.DS_Store
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM python:3.8-slim

WORKDIR /app

# 创建新的sources.list
RUN echo "deb http://mirrors.ustc.edu.cn/debian/ buster main contrib non-free" > /etc/apt/sources.list && \
echo "deb http://mirrors.ustc.edu.cn/debian/ buster-updates main contrib non-free" >> /etc/apt/sources.list && \
echo "deb http://mirrors.ustc.edu.cn/debian-security buster/updates main contrib non-free" >> /etc/apt/sources.list


RUN apt-get update && \
apt-get install -y ffmpeg && \
rm -rf /var/lib/apt/lists/*

COPY . /app


RUN pip install Flask requests

EXPOSE 5001

VOLUME /app/output

CMD ["python", "webui_interface.py"]
10 changes: 9 additions & 1 deletion m3u8dl.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def make_sum():
yield ts_num
ts_num += 1

def dummy_func(downloaded, total, merge_status):
return

class M3u8Download:
"""
Expand All @@ -43,7 +45,7 @@ class M3u8Download:
"""

def __init__(
self, url, workDir, name, max_workers=32, num_retries=999, base64_key=None
self, url, workDir, name, max_workers=32, num_retries=999, base64_key=None, progress_callback=dummy_func
):

self._url = url
Expand All @@ -52,11 +54,13 @@ def __init__(
self._name = name
self._max_workers = max_workers
self._num_retries = num_retries
self._progress_callback = progress_callback
if not os.path.exists(os.path.join(os.getcwd(), self._workDir)):
os.makedirs(os.path.join(os.getcwd(), self._workDir))
self._file_path = os.path.join(os.getcwd(), self._workDir, self._name)
if os.path.exists(self._file_path + ".mp4"):
print(f"File '{self._file_path}.mp4' already exists, skip download")
self._progress_callback(100, 100, 2)
return
self._front_url = None
self._ts_url_list = []
Expand Down Expand Up @@ -95,9 +99,11 @@ def signal_handler(sig, frame):
self._num_retries,
)
if self._success_sum == self._ts_sum:
self._progress_callback(self._success_sum, self._ts_sum, 1)
self.output_mp4()
self.delete_file()
print(f"Download successfully --> {self._name}")
self._progress_callback(self._success_sum, self._ts_sum, 2)

def updateSignature(self):
self.timestamp = str(int(time.time()))
Expand Down Expand Up @@ -250,6 +256,8 @@ def download_ts(self, ts_url, name, num_retries):
self.download_ts(ts_url, name, num_retries - 1)
else:
self._success_sum += 1

self._progress_callback(self._success_sum, self._ts_sum, 0)
except Exception as e:
if os.path.exists(name):
os.remove(name)
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
requests
windows-curses
Flask
60 changes: 60 additions & 0 deletions webui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="ch">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=0.5" />
<link rel="stylesheet" href="styles.css" />
<title>沿河下载器</title>
</head>
<body>
<div class="container">
<button id="newTaskButton" class="btn blue">新建任务</button>
<div id="taskList">

</div>
</div>

<!-- Popup for creating a new task -->
<div id="taskPopup" class="popup">
<div class="popup-content">
<span class="close">×</span>
<form id="taskForm">
<div class="form-group">
<label for="courseId">课程ID号:</label>
<input
type="text"
id="courseId"
name="courseId"
class="input-field"
/>
<button type="button" class="btn" onclick="fetchCourseNumber()">
获取课程信息
</button>
</div>
<div class="form-group">
<label for="downloadType">下载类型:</label>
<select id="downloadType" name="downloadType" class="input-field">
<option value="1">摄像头</option>
<option value="2">电脑屏幕</option>
</select>
</div>
<div class="form-group">
<label id="courseName11">课程名:</label>
<label id="professor11">老师:</label>
</div>
<div class="form-group">
<label for="courses">选择课程编号:</label>
<button type="button" class="btn blue" onclick="selectAll(true);">全选</button>
<button type="button" class="btn blue" onclick="selectAll(false);">全不选</button>
<ul id="courseList">
<li data-value="1">请获取课程信息</li>
</ul>
</div>
<button type="submit" class="btn blue">新建任务</button>
</form>
</div>
</div>

<script src="script.js"></script>
</body>
</html>
191 changes: 191 additions & 0 deletions webui/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
document.getElementById("newTaskButton").onclick = function () {
document.getElementById("taskPopup").style.display = "block";
};

document.getElementsByClassName("close")[0].onclick = function () {
document.getElementById("taskPopup").style.display = "none";
};

// Implement the logic to fetch course number and handle form submission
function fetchCourseNumber() {
fetch(`/get_course?course_id=${document.getElementById("courseId").value}`)
.then((response) => response.json())
.then((data) => {
console.log(data);
document.getElementById("courseList").innerHTML = ``;
document.getElementById("courseName11").innerHTML = `课程名: <b>${
data.courseName == "" ? "未知" : data.courseName
}</b>`;
document.getElementById("professor11").innerHTML = `老师: <b>${
data.professor == "" ? "未知" : data.professor
}</b>`;
let courseListHTML = "";
for (let i = 0; i < data.videoList.length; i++) {
courseListHTML += `<li data-value="${i}">${data.videoList[i].title}</li>`;
}
document.getElementById("courseList").innerHTML = courseListHTML;
document.querySelectorAll("#courseList li").forEach((item) => {
item.addEventListener("click", () => {
item.classList.toggle("selected");
});
});
})
.catch((error) => console.error("Error:", error));
}

document.getElementById("taskForm").onsubmit = function (event) {
event.preventDefault();
let courseId = document.getElementById("courseId").value;
if (courseId.trim() == "") {
alert("课程名不能为空");
return;
}
let downloadType = document.getElementById("downloadType").value;
let selected_index = [];
let courseList = document.getElementById("courseList");
for (let i = 0; i < courseList.childNodes.length; i++) {
let child = courseList.childNodes[i];
if (child.className == "selected") {
selected_index.push(child.getAttribute("data-value"));
}
}
let course_number = selected_index.join(",");
fetch("/new_task", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
course_id: courseId.trim(),
course_number: course_number,
download_version: downloadType,
}),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
document.getElementById("taskPopup").style.display = "none";
})
.catch((error) => console.error("Error:", error));
};

function getDownloadStatusText(task_obj) {
const merge_status = task_obj["merge_status"];
const cur = task_obj["cur"];
const tot = task_obj["tot"];
const cancel = task_obj["canceled"];
if (cancel) {
return "已取消";
}
if (merge_status == 0) {
if (cur == 0) {
return "等待中...";
} else {
return `下载中...(${((cur / tot) * 100).toFixed(2)} %)`;
}
} else if (merge_status == 1) {
return "合并视频中...";
} else if (merge_status == 2) {
return "已完成";
} else {
return "未知状态";
}
}

function cancelTask(btn) {
let uuid = btn.getAttribute("data-task-uuid");
console.log(uuid);
fetch(`/kill_task?uuid=${uuid}`)
.then((response) => response.json())
.then((data) => {
console.log(data);
let remove_node = document.getElementById(`${uuid}-task`);
if(remove_node != null) {
remove_node.parentNode.removeChild(remove_node);
}
})
.catch((error) => console.error("Error:", error));
}

setInterval(() => {
const addElement = (task_obj) => {
if (task_obj["canceled"]) {
return;
}
const download_version =
task_obj["download_type"] == 2 ? "电脑屏幕" : "摄像头";
const html = `
<div class="task" id="${task_obj["uuid"]}-task">
<div class="task-info">
<span>${task_obj["name"]}(${download_version})</span>
<div class="status-container">
<span class="status" id="${
task_obj["uuid"]
}-status">${getDownloadStatusText(task_obj)}</span>
<button class="cancel-btn" data-task-uuid="${
task_obj["uuid"]
}" onclick="cancelTask(this);">×</button>
</div>
</div>
<div class="progress-bar">
<div class="progress" id="${task_obj["uuid"]}-progress"></div>
</div>
</div>
`;
let taskList = document.getElementById("taskList");
taskList.innerHTML = html + taskList.innerHTML;
};
const updateElement = (task_obj) => {
const uuid = task_obj["uuid"];
const status_ele = document.getElementById(`${task_obj["uuid"]}-status`);
const progress_ele = document.getElementById(
`${task_obj["uuid"]}-progress`
);
status_ele.innerText = getDownloadStatusText(task_obj);
const progress = (100 * task_obj["cur"]) / task_obj["tot"];
progress_ele.style.width = `${progress.toFixed(2)}%`;
};
const removeCanceledElement = (uuid_arr) => {
let all_task_elem = document.getElementsByClassName("task");
for(let i=0;i<all_task_elem.length;i++) {
const uuid = all_task_elem[i].getAttribute("id").replace("-task", "");
if(!uuid_arr.includes(uuid)) {
all_task_elem[i].parentNode.removeChild(all_task_elem[i]);
}
}
}
fetch("/get_status")
.then((response) => response.json())
.then((data) => {
// console.log(data);
let uuid_arr = [];
for (let i = 0; i < data.length; i++) {
const uuid = data[i]["uuid"];
if(!data[i]["canceled"]) {
uuid_arr.push(uuid);
}
let exist_ele = document.getElementById(`${uuid}-task`);
if (exist_ele == null) {
addElement(data[i]);
} else {
updateElement(data[i]);
}
}
removeCanceledElement(uuid_arr);
})
.catch((error) => console.error("Error:", error));
}, 1000);

const listItems = document.querySelectorAll("#courseList li");
listItems.forEach((item) => {
item.addEventListener("click", () => {
item.classList.toggle("selected");
});
});

function selectAll(select) {
let list = document.getElementById("courseList");
for(let i=0;i<list.childNodes.length;i++) {
list.childNodes[i].className = select ? "selected" : "";
}
}
Loading

0 comments on commit 55fc1df

Please sign in to comment.