mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-08-12 17:10:37 +00:00
883 lines
25 KiB
HTML
883 lines
25 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta name="referrer" content="no-referrer" />
|
||
<link rel="icon" href="docs/netease.png" />
|
||
<meta name="referrer" content="no-referrer" />
|
||
<link rel="icon" href="docs/netease.png" />
|
||
<title>云小编任务中心 - 网易云音乐 API Enhanced</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
padding: 20px;
|
||
}
|
||
|
||
.container {
|
||
max-width: 600px;
|
||
margin: 40px auto;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 32px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
h1 {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
text-align: center;
|
||
}
|
||
|
||
.subtitle {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-bottom: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.login-link {
|
||
display: block;
|
||
margin-bottom: 20px;
|
||
color: #666;
|
||
font-size: 14px;
|
||
text-decoration: none;
|
||
text-align: center;
|
||
}
|
||
|
||
.login-link:hover {
|
||
color: #333;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* ---- Section ---- */
|
||
.section {
|
||
margin-bottom: 24px;
|
||
padding-bottom: 20px;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.section:last-of-type {
|
||
border-bottom: none;
|
||
margin-bottom: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
/* ---- Form ---- */
|
||
.form-group {
|
||
margin-bottom: 16px;
|
||
text-align: left;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: #555;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
label .tag {
|
||
display: inline-block;
|
||
font-size: 11px;
|
||
font-weight: 400;
|
||
padding: 1px 6px;
|
||
border-radius: 3px;
|
||
margin-left: 6px;
|
||
}
|
||
|
||
label .tag.r {
|
||
background: #fee2e2;
|
||
color: #991b1b;
|
||
}
|
||
|
||
label .tag.o {
|
||
background: #fef3c7;
|
||
color: #92400e;
|
||
}
|
||
|
||
label .tag.g {
|
||
background: #d1fae5;
|
||
color: #065f46;
|
||
}
|
||
|
||
input[type="text"],
|
||
input[type="number"],
|
||
textarea {
|
||
width: 100%;
|
||
padding: 10px 14px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
outline: none;
|
||
font-family: inherit;
|
||
transition: border-color 0.2s;
|
||
}
|
||
|
||
input[type="text"]:focus,
|
||
input[type="number"]:focus,
|
||
textarea:focus {
|
||
border-color: #333;
|
||
}
|
||
|
||
textarea {
|
||
resize: vertical;
|
||
}
|
||
|
||
.row {
|
||
display: flex;
|
||
gap: 12px;
|
||
}
|
||
|
||
.row .form-group {
|
||
flex: 1;
|
||
}
|
||
|
||
.quick-fill {
|
||
margin-top: 5px;
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
.quick-fill span {
|
||
color: #0066cc;
|
||
cursor: pointer;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.quick-fill span:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.btn {
|
||
display: block;
|
||
width: 100%;
|
||
padding: 12px;
|
||
background: #333;
|
||
color: white;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
transition: background 0.2s ease;
|
||
border: none;
|
||
text-align: center;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.btn:hover {
|
||
background: #555;
|
||
}
|
||
|
||
.btn:disabled {
|
||
background: #ccc;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-sm {
|
||
display: inline-block;
|
||
width: auto;
|
||
padding: 6px 16px;
|
||
background: #333;
|
||
color: white;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
transition: background 0.2s ease;
|
||
border: none;
|
||
text-align: center;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.btn-sm:hover {
|
||
background: #555;
|
||
}
|
||
|
||
.btn-sm:disabled {
|
||
background: #ccc;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-sm.green {
|
||
background: #059669;
|
||
}
|
||
|
||
.btn-sm.green:hover {
|
||
background: #047857;
|
||
}
|
||
|
||
.btn-sm.green:disabled {
|
||
background: #a7f3d0;
|
||
}
|
||
|
||
.btn-sm.red {
|
||
background: #dc2626;
|
||
}
|
||
|
||
.btn-sm.red:hover {
|
||
background: #b91c1c;
|
||
}
|
||
|
||
.btn-sm.red:disabled {
|
||
background: #fca5a5;
|
||
}
|
||
|
||
.btn-sm.gray {
|
||
background: #6b7280;
|
||
}
|
||
|
||
.btn-sm.gray:hover {
|
||
background: #4b5563;
|
||
}
|
||
|
||
.btn-sm.gray:disabled {
|
||
background: #d1d5db;
|
||
}
|
||
|
||
.result {
|
||
margin-top: 16px;
|
||
padding: 12px 16px;
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
text-align: left;
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
font-family: monospace;
|
||
}
|
||
|
||
.result.success {
|
||
background: #d1fae5;
|
||
color: #065f46;
|
||
}
|
||
|
||
.result.error {
|
||
background: #fee2e2;
|
||
color: #991b1b;
|
||
}
|
||
|
||
.result.info {
|
||
background: #e0f2fe;
|
||
color: #0369a1;
|
||
}
|
||
|
||
.footer-link {
|
||
text-align: center;
|
||
margin-top: 24px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.footer-link a {
|
||
color: #666;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.footer-link a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* ---- Info Card ---- */
|
||
.info-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 16px;
|
||
background: #f9fafb;
|
||
border-radius: 8px;
|
||
border: 1px solid #eee;
|
||
}
|
||
|
||
.info-card .avatar {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
background: #e5e7eb;
|
||
}
|
||
|
||
.info-card .info-text {
|
||
flex: 1;
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
|
||
.info-card .btn-sm {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
#userPoint {
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* ---- Song Review ---- */
|
||
.song-review {
|
||
margin-top: 16px;
|
||
padding: 16px;
|
||
background: #f9fafb;
|
||
border-radius: 8px;
|
||
border: 1px solid #eee;
|
||
}
|
||
|
||
.song-review .cover {
|
||
width: 100px;
|
||
height: 100px;
|
||
border-radius: 6px;
|
||
object-fit: cover;
|
||
background: #e5e7eb;
|
||
display: block;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.song-review .song-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.song-review audio {
|
||
width: 100%;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.song-review .song-tag {
|
||
font-size: 13px;
|
||
color: #666;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.song-review .btn-group {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.song-review .lyric {
|
||
font-size: 13px;
|
||
color: #555;
|
||
background: #fff;
|
||
padding: 10px 12px;
|
||
border-radius: 6px;
|
||
border: 1px solid #e5e7eb;
|
||
white-space: pre-wrap;
|
||
max-height: 160px;
|
||
overflow-y: auto;
|
||
font-family: monospace;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.status-text {
|
||
font-size: 14px;
|
||
color: #888;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="container">
|
||
<h1>云小编任务中心</h1>
|
||
<p class="subtitle">管理云音乐审核任务、签到与会员权益领取</p>
|
||
|
||
<a href="/qrlogin-nocookie.html" class="login-link">还没登录?点击登录</a>
|
||
|
||
<!-- Cookie -->
|
||
<div class="form-group">
|
||
<label for="cookie">Cookie <span class="tag o">可选</span></label>
|
||
<textarea id="cookie" placeholder="留空则默认读取本地存储的登录态" rows="2"></textarea>
|
||
<div class="quick-fill">
|
||
<span onclick="loadLocalCookie()">读取本地 Cookie</span>
|
||
<span onclick="clearCookie()">清除 Cookie</span>
|
||
<span onclick="saveCookie()">保存 Cookie</span>
|
||
<span onclick="loadAll()">一键载入</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="section-header">
|
||
<span class="section-title">用户信息</span>
|
||
<button class="btn-sm" id="userGet">获取用户详情</button>
|
||
</div>
|
||
<div class="info-card" id="user">
|
||
<img src="docs/netease.png" alt="头像" class="avatar" id="userAvatar" />
|
||
<span class="info-text" id="userName">未登录</span>
|
||
<span id="userPoint">0</span>
|
||
<button class="btn-sm green" id="userSign" disabled>签到</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="section-header">
|
||
<span class="section-title">会员领取</span>
|
||
<button class="btn-sm" id="vipGet">获取会员详情</button>
|
||
</div>
|
||
<div class="info-card" id="vip">
|
||
<span class="info-text" id="vipStatus">未载入</span>
|
||
<button class="btn-sm" id="vipCollect" disabled>领取</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="section-header">
|
||
<span class="section-title">审核任务</span>
|
||
<button class="btn-sm" id="taskGet">获取任务详情</button>
|
||
</div>
|
||
<div class="info-card" id="task">
|
||
<span class="info-text" id="taskInfo">[<span id="taskCount">0</span>/<span id="taskGoal">0</span>] 审核歌曲赚贡献分 (+<span id="taskPoint">0</span>)</span>
|
||
<button class="btn-sm" id="taskStart" disabled>去完成</button>
|
||
</div>
|
||
|
||
<!-- Song Review -->
|
||
<div class="song-review" id="song" style="display: none;">
|
||
<img alt="封面" class="cover" id="songCover" />
|
||
<div class="song-title" id="songTitle">未载入</div>
|
||
<audio controls id="songAudio"></audio>
|
||
<div class="song-tag" id="songTag"></div>
|
||
<div class="btn-group">
|
||
<button class="btn-sm green" id="songApprove" disabled>同意</button>
|
||
<button class="btn-sm red" id="songReject" disabled>否决</button>
|
||
<button class="btn-sm gray" id="songSkip" disabled>跳过 (不计次数)</button>
|
||
</div>
|
||
<div class="lyric" id="songLyric">[00:00.00] 暂无歌词</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="result" class="result" style="display: none;"></div>
|
||
|
||
<div class="footer-link">
|
||
<a href="/">返回首页</a>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
var k_cookie = 'ncm_cookie';
|
||
var cookie = localStorage.getItem(k_cookie) || '';
|
||
|
||
/* ---- DOM refs ---- */
|
||
var cookieInput = document.getElementById('cookie');
|
||
var resultDiv = document.getElementById('result');
|
||
|
||
/* ---- Init ---- */
|
||
if (cookie) {
|
||
cookieInput.value = cookie;
|
||
}
|
||
|
||
/* ---- Cookie ---- */
|
||
window.loadLocalCookie = function () {
|
||
var local = localStorage.getItem(k_cookie);
|
||
if (local) {
|
||
cookie = local;
|
||
cookieInput.value = local;
|
||
showResult('已成功读取本地 Cookie', 'success');
|
||
} else {
|
||
showResult('未在本地发现登录 Cookie,请先登录或手动粘贴', 'error');
|
||
}
|
||
};
|
||
|
||
window.clearCookie = function () {
|
||
cookie = '';
|
||
cookieInput.value = '';
|
||
localStorage.removeItem(k_cookie);
|
||
showResult('已清除本地 Cookie', 'info');
|
||
};
|
||
|
||
window.saveCookie = function () {
|
||
var ck = getCookie()
|
||
if (ck) localStorage.setItem(k_cookie, ck)
|
||
showResult('已保存本地 Cookie', 'info');
|
||
}
|
||
|
||
/* ---- Result ---- */
|
||
function hideResult() {
|
||
resultDiv.style.display = 'none';
|
||
}
|
||
|
||
function showResult(message, type) {
|
||
resultDiv.textContent = message;
|
||
resultDiv.className = 'result ' + type;
|
||
resultDiv.style.display = 'block';
|
||
}
|
||
|
||
function getCookie() {
|
||
var ck = cookieInput.value.trim();
|
||
if (ck) cookie = ck;
|
||
return ck || cookie || '';
|
||
}
|
||
|
||
/**
|
||
* 发起请求 (兼容旧版)
|
||
* @param {string} url
|
||
* @param {Record<string,string>} params
|
||
* @param {(resp:Record<string,any>)=>void} done
|
||
*/
|
||
function request(url, params, done) {
|
||
var xhr = new XMLHttpRequest();
|
||
xhr.responseType = 'json';
|
||
xhr.timeout = 1e4;
|
||
xhr.onload = function () {
|
||
var r = xhr.response;
|
||
if (r.code !== 200) {
|
||
showResult('错误 ' + r.code + ': ' + (r.message || '未知错误'), 'error');
|
||
} else {
|
||
done(r);
|
||
}
|
||
};
|
||
xhr.onerror = function () {
|
||
showResult('网络请求失败: ' + xhr.statusText, 'error');
|
||
};
|
||
var ck = getCookie();
|
||
if (ck) params.cookie = ck;
|
||
var s = '?_=' + Date.now();
|
||
for (var k in params) {
|
||
s += '&' + k + '=' + encodeURIComponent(params[k]);
|
||
}
|
||
xhr.open('GET', url + s);
|
||
xhr.send();
|
||
}
|
||
|
||
/// 用户信息 ///
|
||
var userAvatar = document.getElementById('userAvatar');
|
||
var userName = document.getElementById('userName');
|
||
var userPoint = document.getElementById('userPoint');
|
||
var userSign = document.getElementById('userSign');
|
||
var userGet = document.getElementById('userGet');
|
||
|
||
userGet.onclick = function () {
|
||
request('rep/ugc/user/get', {}, function (res) {
|
||
var d = res.data;
|
||
if (d.imgUrl) userAvatar.src = d.imgUrl + '?param=50y50';
|
||
userName.textContent = d.name || '游客' + d.id;
|
||
userPoint.textContent = d.availablePoints;
|
||
userSign.disabled = d.signed;
|
||
showResult('用户信息加载成功', 'success');
|
||
});
|
||
};
|
||
|
||
userSign.onclick = function () {
|
||
if (!userSign.disabled) {
|
||
userSign.disabled = true;
|
||
request('rep/ugc/user/sign', {}, function (res) {
|
||
var d = res.data;
|
||
userSign.disabled = d;
|
||
showResult('签到' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||
if (d) userGet.click();
|
||
});
|
||
}
|
||
};
|
||
|
||
/// 会员领取 ///
|
||
var vipStatus = document.getElementById('vipStatus');
|
||
var vipCollect = document.getElementById('vipCollect');
|
||
var vipGet = document.getElementById('vipGet');
|
||
|
||
vipGet.onclick = function () {
|
||
request('rep/ugc/user/vip', {}, function (res) {
|
||
var d = res.data;
|
||
vipStatus.textContent = d.status + ': ' + d.title;
|
||
vipCollect.disabled = d.status !== 20;
|
||
showResult('会员详情加载成功', 'success');
|
||
});
|
||
};
|
||
|
||
vipCollect.onclick = function () {
|
||
if (!vipCollect.disabled) {
|
||
vipCollect.disabled = true;
|
||
request('rep/ugc/user/collect-vip', {}, function (res) {
|
||
var d = res.data;
|
||
vipCollect.disabled = d;
|
||
showResult('领取' + (d ? '成功 ✓' : '失败 ✗'), d ? 'success' : 'error');
|
||
});
|
||
}
|
||
};
|
||
|
||
/// 审核任务 ///
|
||
var taskCount = document.getElementById('taskCount');
|
||
var taskGoal = document.getElementById('taskGoal');
|
||
var taskPoint = document.getElementById('taskPoint');
|
||
var taskStartBtn = document.getElementById('taskStart');
|
||
var taskGetBtn = document.getElementById('taskGet');
|
||
|
||
taskGetBtn.onclick = function () {
|
||
request('rep/ugc/activity/get', {}, function (res) {
|
||
var d = res.data;
|
||
taskCount.textContent = d.count;
|
||
taskGoal.textContent = d.goalCount;
|
||
taskPoint.textContent = d.points;
|
||
// 注:超过 100 可能有 bug,导致 thinktank/audit/resource/detail 获取的任务 ID 一直是 5002,目标数量也不对,暂时限制前两个任务
|
||
taskStartBtn.disabled = d.activityId !== 5001 && d.activityId !== 5002; // 5001: 1-50, 5002: 51-100
|
||
showResult('任务详情加载成功', 'success');
|
||
// 任务完成,领取积分
|
||
if (d.count >= d.goalCount) {
|
||
request('rep/ugc/activity/collect', { activityId: d.activityId }, function (res) {
|
||
var d = res.data;
|
||
showResult('积分领取' + (d ? '成功,可以兑换会员了!' : '失败'), d ? 'success' : 'error');
|
||
// 刷新任务状态
|
||
if (d) loadAll();
|
||
});
|
||
}
|
||
});
|
||
};
|
||
|
||
taskStartBtn.onclick = function () {
|
||
if (!taskStartBtn.disabled) {
|
||
songAudio.pause();
|
||
examInit();
|
||
}
|
||
};
|
||
|
||
/// 歌曲审核区域 ///
|
||
var song = document.getElementById('song');
|
||
var songCover = document.getElementById('songCover');
|
||
var songTitle = document.getElementById('songTitle');
|
||
var songAudio = document.getElementById('songAudio');
|
||
var songTag = document.getElementById('songTag');
|
||
var songApprove = document.getElementById('songApprove');
|
||
var songReject = document.getElementById('songReject');
|
||
var songSkip = document.getElementById('songSkip');
|
||
var songLyric = document.getElementById('songLyric');
|
||
|
||
var examType = 'emotionEnter';
|
||
// 考试初始化、检查状态
|
||
function examInit() {
|
||
request('rep/ugc/exam/info/get', { examType: examType }, function (res) {
|
||
var d = res.data;
|
||
switch (d.process) {
|
||
case 'whole_exam_end':
|
||
// 通过考试
|
||
if (d.hasPassExamination) {
|
||
taskStart();
|
||
return;
|
||
}
|
||
request('rep/ugc/exam/result/get', { examType: examType, taskId: d.taskId }, function (res) {
|
||
var d = res.data;
|
||
showResult('考试未通过:正确数:' + d.wrightNum + ',正确率:' + d.wrightRate, 'error');
|
||
});
|
||
case 'no':
|
||
// 未通过或未开始
|
||
request('rep/ugc/exam/start', { examType: examType }, function (res) {
|
||
examStart(res.data.taskId);
|
||
});
|
||
break;
|
||
case 'process':
|
||
// 正在考试
|
||
examStart(d.taskId);
|
||
break;
|
||
default:
|
||
showResult('未知考试进度:' + d.process, 'error');
|
||
return;
|
||
}
|
||
// 在上个信息不为异常时显示考试中提示
|
||
if (d.process !== 'whole_exam_end' && !resultDiv.className.endsWith('error')) showResult('正在考试,请认真审题!', 'info');
|
||
});
|
||
}
|
||
// 考试取题开始
|
||
function examStart(taskId) {
|
||
request('rep/ugc/exam/question/single/get', { examType: examType, taskId: taskId }, function (res) {
|
||
var d = res.data;
|
||
|
||
songCover.src = d.coverUrl + '?param=100y100';
|
||
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.questionContent + '?';
|
||
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||
songLyric.scrollTop = 0;
|
||
// 有时候就是没有播放链接,只能根据歌词硬审
|
||
if (d.songUrl) {
|
||
songAudio.src = d.songUrl;
|
||
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||
} else {
|
||
songAudio.src = ''; // 清理播放器
|
||
}
|
||
songApprove.onclick = function () { if (!songApprove.disabled) examSubmit(taskId, d.questionId, 'A') };
|
||
songReject.onclick = function () { if (!songReject.disabled) examSubmit(taskId, d.questionId, 'B') };
|
||
songSkip.onclick = null;
|
||
|
||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||
song.style.display = 'block';
|
||
|
||
setTimeout(function () {
|
||
songApprove.disabled = songReject.disabled = false;
|
||
}, 3e3);
|
||
});
|
||
}
|
||
// 考试提交
|
||
function examSubmit(taskId, questionId, answer) {
|
||
songAudio.pause();
|
||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||
request(
|
||
'rep/ugc/exam/submit',
|
||
{ examType: examType, taskId: taskId, questionId: questionId, answer: answer },
|
||
function (res) {
|
||
var d = res.data;
|
||
if (d.result) {
|
||
showResult('回答正确,加载下一首...', 'success');
|
||
} else {
|
||
showResult('回答错误:' + d.analysis, 'error');
|
||
}
|
||
examInit();
|
||
},
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 获取任务
|
||
*/
|
||
function taskStart() {
|
||
request('thinktank/audit/resource/detail', { type: '4' }, function (res) {
|
||
var d = res.data;
|
||
|
||
if (d.auditCount >= 50) {
|
||
request('rep/ugc/activity/collect', { activityId: '5001' }, function (res) {
|
||
var d = res.data;
|
||
showResult('积分领取' + (d ? '成功,可以兑换会员了!' : '失败'), d ? 'success' : 'error');
|
||
// 刷新任务状态
|
||
if (d) {
|
||
vipGet.click();
|
||
taskGetBtn.click();
|
||
}
|
||
});
|
||
songAudio.pause()
|
||
return;
|
||
}
|
||
|
||
songCover.src = d.coverUrl + '?param=100y100';
|
||
songTitle.textContent = '[' + d.resId + '] ' + d.resName + ' - ' + d.artists;
|
||
songTag.textContent = '[' + (d.auditCount + 1) + '/' + d.auditTaskCount + '] 当前结果: ' + d.initResult + '?';
|
||
songLyric.textContent = d.lyric ? d.transLyric ? lrctran(d.lyric, d.transLyric) : d.lyric : '[00:00.00] 暂无歌词';
|
||
songLyric.scrollTop = 0;
|
||
songAudio.src = d.songUrl;
|
||
songAudio.play().catch(function () { /* 自动播放被浏览器阻止 */ });
|
||
|
||
songApprove.onclick = function () { if (!songApprove.disabled) taskSubmit(d.taskId, '1'); };
|
||
songReject.onclick = function () { if (!songReject.disabled) taskSubmit(d.taskId, '2'); };
|
||
songSkip.onclick = function () { if (!songSkip.disabled) taskSubmit(d.taskId, '3'); };
|
||
|
||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||
song.style.display = 'block';
|
||
|
||
setTimeout(function () {
|
||
songApprove.disabled = songReject.disabled = songSkip.disabled = false;
|
||
}, 3e3);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 提交任务
|
||
* @param {string} taskId
|
||
* @param {'1'|'2'|'3'} judgement
|
||
*/
|
||
function taskSubmit(taskId, judgement) {
|
||
songAudio.pause();
|
||
songApprove.disabled = songReject.disabled = songSkip.disabled = true;
|
||
request(
|
||
'thinktank/audit/resource/update',
|
||
{ type: '4', taskId: taskId, judgement: judgement },
|
||
function (res) {
|
||
var d = res.data;
|
||
if (d.result) {
|
||
showResult((d.test ? '抽查' : '审核') + '提交成功,加载下一首...', 'success');
|
||
taskStart();
|
||
} else if (d.test) {
|
||
showResult('抽查失败: [' + d.dayErrorNum + '/' + d.dayErrorNumStandard + '] ' + d.errorAnalysis, 'error');
|
||
taskStart();
|
||
} else {
|
||
showResult('未知状态: ' + JSON.stringify(d), 'error');
|
||
}
|
||
},
|
||
);
|
||
}
|
||
|
||
/**解析歌词时间戳和文本 */
|
||
function lrctrim(lyrics) {
|
||
var lines = lyrics.split('\n');
|
||
var data = [];
|
||
lines.forEach(function (line, index) {
|
||
var matches = line.match(/\[(\d{2}):(\d{2}[\.:]?\d*)\]/);
|
||
if (matches) {
|
||
var minutes = parseInt(matches[1], 10);
|
||
var seconds = parseFloat(matches[2].replace('.', ':')) || 0;
|
||
var timestamp = minutes * 6e4 + seconds * 1e3;
|
||
var text = line.replace(/\[\d{2}:\d{2}[\.:]?\d*\]/g, '').trim();
|
||
text = text.replace(/\s\s+/g, ' '); // Replace multiple spaces with a single space
|
||
data.push([timestamp, index, text]);
|
||
}
|
||
});
|
||
data.sort(function (a, b) {
|
||
return a[0] - b[0];
|
||
});
|
||
return data;
|
||
}
|
||
/**合并原文歌词和翻译歌词 */
|
||
function lrctran(lyric, tlyric) {
|
||
lyric = lrctrim(lyric);
|
||
tlyric = lrctrim(tlyric);
|
||
var len1 = lyric.length;
|
||
var len2 = tlyric.length;
|
||
var result = '';
|
||
for (var i = 0, j = 0; i < len1 && j < len2; i++) {
|
||
while (lyric[i][0] > tlyric[j][0] && j + 1 < len2) {
|
||
j++;
|
||
}
|
||
if (lyric[i][0] === tlyric[j][0]) {
|
||
tlyric[j][2] = tlyric[j][2].replace('/', '');
|
||
if (tlyric[j][2]) {
|
||
lyric[i][2] += ' (' + tlyric[j][2] + ')';
|
||
}
|
||
j++;
|
||
}
|
||
}
|
||
for (var k = 0; k < len1; k++) {
|
||
var t = lyric[k][0];
|
||
result += '['.concat(
|
||
String(Math.floor(t / 6e4)).padStart(2, '0'),
|
||
':',
|
||
String(Math.floor((t % 6e4) / 1e3)).padStart(2, '0'),
|
||
'.',
|
||
String(t % 1e3).padStart(3, '0'),
|
||
']',
|
||
lyric[k][2],
|
||
'\n',
|
||
);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/// 一键载入 ///
|
||
window.loadAll = function () {
|
||
userGet.click();
|
||
vipGet.click();
|
||
taskGetBtn.click();
|
||
showResult('正在载入所有数据...', 'info');
|
||
};
|
||
|
||
window.loadLocalCookie();
|
||
})();
|
||
</script>
|
||
</body>
|
||
|
||
</html>
|