Netease_url/templates/index.html
2025-08-25 01:24:01 +08:00

685 lines
34 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网易云音乐工具箱</title>
<link href="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/aplayer/1.10.1/APlayer.min.css">
<style>
body {
background-color: #f8f9fa;
color: #333;
}
.container {
max-width: 800px;
}
.form-group {
margin-bottom: 15px;
}
.btn-primary {
margin-top: 20px;
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:hover {
background-color: #0056b3;
border-color: #004085;
}
.btn-success {
margin-top: 20px;
background-color: #28a745;
border-color: #28a745;
}
.btn-success:hover {
background-color: #218838;
border-color: #1e7e34;
}
.btn-warning {
margin-top: 20px;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-warning:hover {
background-color: #e0a800;
border-color: #d39e00;
}
#song-info {
margin-top: 20px;
}
#song-info img {
max-width: 100%;
border-radius: 8px;
}
.alert-info {
background-color: #d1ecf1;
color: #0c5460;
border-color: #bee5eb;
}
/* 歌曲/歌单标题过长自动省略号 */
.song-title, .playlist-title {
display: inline-block;
max-width: 180px;
vertical-align: middle;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 歌单列表按钮不换行 */
.list-group-item .select-song {
flex-shrink: 0;
margin-left: 10px;
}
/* 歌词区域美化 */
.lyric-box {
max-height: 180px;
overflow-y: auto;
background: linear-gradient(90deg,#f7f7fa 60%,#f0f4fa 100%);
border-radius: 8px;
padding: 12px 16px;
font-size: 15px;
color: #222;
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
line-height: 1.7;
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">网易云音乐工具箱</h1>
<div class="card shadow-sm">
<div class="card-body">
<form id="main-form">
<div class="mb-3">
<label class="form-label">功能选择</label>
<select id="mode-select" class="form-select">
<option value="search">歌曲搜索</option>
<option value="parse">单曲解析</option>
<option value="playlist">歌单解析</option>
<option value="album">专辑解析</option>
<option value="download">音乐下载</option>
</select>
</div>
<div id="search-area">
<div class="mb-3">
<label for="search_keywords" class="form-label">搜索关键词</label>
<input type="text" id="search_keywords" class="form-control" placeholder="输入关键词进行搜索">
</div>
<div class="mb-3">
<label for="search_limit" class="form-label">返回数量</label>
<input type="number" id="search_limit" class="form-control" value="10" min="1" max="50">
</div>
<div class="text-center">
<button type="button" id="search-btn" class="btn btn-success w-50">搜索</button>
</div>
</div>
<div id="parse-area" style="display:none;">
<div class="mb-3">
<label for="song_ids" class="form-label">歌曲ID或URL</label>
<input type="text" id="song_ids" class="form-control" placeholder="输入歌曲ID或URL">
</div>
<div class="mb-3">
<label for="level" class="form-label">音质选择</label>
<select id="level" class="form-select">
<option value="standard">标准音质</option>
<option value="exhigh">极高音质</option>
<option value="lossless">无损音质</option>
<option value="hires">Hires音质</option>
<option value="sky">沉浸环绕声</option>
<option value="jyeffect">高清环绕声</option>
<option value="jymaster">超清母带</option>
</select>
</div>
<div class="text-center">
<button type="button" id="parse-btn" class="btn btn-primary w-50">解析</button>
</div>
</div>
<div id="playlist-area" style="display:none;">
<div class="mb-3">
<label for="playlist_id" class="form-label">歌单ID或链接</label>
<input type="text" id="playlist_id" class="form-control" placeholder="输入歌单ID或网易云歌单链接">
</div>
<div class="text-center">
<button type="button" id="playlist-btn" class="btn btn-warning w-50">解析歌单</button>
</div>
</div>
<div id="album-area" style="display:none;">
<div class="mb-3">
<label for="album_id" class="form-label">专辑ID或链接</label>
<input type="text" id="album_id" class="form-control" placeholder="输入专辑ID或网易云专辑链接">
</div>
<div class="text-center">
<button type="button" id="album-btn" class="btn btn-info w-50">解析专辑</button>
</div>
</div>
<div id="download-area" style="display:none;">
<div class="mb-3">
<label for="download_id" class="form-label">音乐ID或URL</label>
<input type="text" id="download_id" class="form-control" placeholder="输入音乐ID或网易云音乐链接">
</div>
<div class="mb-3">
<label for="download_quality" class="form-label">下载音质</label>
<select id="download_quality" class="form-select">
<option value="standard">标准音质</option>
<option value="exhigh">极高音质</option>
<option value="lossless" selected>无损音质</option>
<option value="hires">Hires音质</option>
<option value="sky">沉浸环绕声</option>
<option value="jyeffect">高清环绕声</option>
<option value="jymaster">超清母带</option>
</select>
</div>
<div class="text-center">
<button type="button" id="download-btn" class="btn btn-success w-50">下载音乐</button>
</div>
<div id="download-progress" class="mt-3 d-none">
<div class="progress">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%"></div>
</div>
<div class="text-center mt-2">
<small class="text-muted">正在下载并写入元信息...</small>
</div>
</div>
</div>
</form>
</div>
</div>
<!-- 搜索结果列表 -->
<div id="search-result" class="mt-4 d-none">
<h5>搜索结果:</h5>
<ul class="list-group" id="search-list"></ul>
</div>
<!-- 结果展示区域 -->
<div id="song-info" class="alert alert-info d-none mt-4 p-0 border-0" style="box-shadow:0 2px 8px rgba(0,0,0,0.07);">
<div class="row g-0 align-items-stretch">
<div class="col-md-8 p-3 d-flex flex-column justify-content-between">
<h4 class="mb-2" id="song_name" style="font-weight:700;"></h4>
<div class="mb-2"><span class="badge bg-primary me-2">歌手</span><span id="artist_names"></span></div>
<div class="mb-2"><span class="badge bg-secondary me-2">专辑</span><span id="song_alname"></span></div>
<div class="mb-2"><span class="badge bg-success me-2">音质</span><span id="song_level"></span></div>
<div class="mb-2"><span class="badge bg-warning text-dark me-2">大小</span><span id="song_size"></span></div>
<div class="mb-2">
<button id="show-big-pic" type="button" class="btn btn-outline-info btn-sm me-2" style="vertical-align:middle;">显示大图</button>
</div>
<div class="mb-2"><span class="badge bg-info text-dark me-2">链接</span><a id="song_url" href="" target="_blank">点击下载</a></div>
<div class="mb-2"><span class="badge bg-dark me-2">歌词</span></div>
<div class="lyric-box" id="lyric"></div>
</div>
</div>
<div class="row g-0">
<div class="col-12 p-3 pt-0">
<div id="aplayer"></div>
</div>
</div>
</div>
<!-- 歌单解析结果 -->
<div id="playlist-result" class="mt-4 d-none">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<img id="playlist-cover" src="" alt="cover" style="width:60px;height:60px;object-fit:cover;border-radius:8px;margin-right:15px;">
<div>
<h5 id="playlist-name" class="mb-1"></h5>
<div class="text-muted" id="playlist-creator"></div>
</div>
</div>
<div id="playlist-desc" class="mb-2 text-secondary small"></div>
<div><span id="playlist-count"></span> 首歌</div>
</div>
</div>
<ul class="list-group mt-3" id="playlist-tracks"></ul>
</div>
<!-- 专辑解析结果 -->
<div id="album-result" class="mt-4 d-none">
<div class="card">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<img id="album-cover" src="" alt="cover" style="width:60px;height:60px;object-fit:cover;border-radius:8px;margin-right:15px;">
<div>
<h5 id="album-name" class="mb-1"></h5>
<div class="text-muted" id="album-artist"></div>
</div>
</div>
<div id="album-desc" class="mb-2 text-secondary small"></div>
<div><span id="album-count"></span> 首歌</div>
</div>
</div>
<ul class="list-group mt-3" id="album-tracks"></ul>
</div>
</div>
<!-- Modal for big picture -->
<div class="modal fade" id="bigPicModal" tabindex="-1" aria-labelledby="bigPicModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="bigPicModalLabel">大图预览</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center">
<img id="big-pic-img" src="" alt="大图" style="max-width:100%;max-height:60vh;border-radius:10px;box-shadow:0 2px 12px rgba(0,0,0,0.12);">
</div>
</div>
</div>
</div>
<footer class="footer mt-5 py-3 bg-light border-top">
<div class="container text-center text-muted small">
<span>网易云音乐工具箱 &copy; 2025 | Powered by Suxiaoqingx &amp; Bootstrap | <a href="https://github.com/Suxiaoqinx/Netease_url" target="_blank">GitHub</a></span>
</div>
</footer>
<script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/aplayer/1.10.1/APlayer.min.js"></script>
<script src="https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/twitter-bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
<script>
$(document).ready(function() {
function lrctrim(lyrics) {
const lines = lyrics.split('\n');
const data = [];
lines.forEach((line, index) => {
const matches = line.match(/\[(\d{2}):(\d{2}[\.:]?\d*)]/);
if (matches) {
const minutes = parseInt(matches[1], 10);
const seconds = parseFloat(matches[2].replace('.', ':')) || 0;
const timestamp = minutes * 60000 + seconds * 1000;
let 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((a, b) => a[0] - b[0]);
return data;
}
function lrctran(lyric, tlyric) {
lyric = lrctrim(lyric);
tlyric = lrctrim(tlyric);
let len1 = lyric.length;
let len2 = tlyric.length;
let result = "";
for (let 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 (let i = 0; i < len1; i++) {
let t = lyric[i][0];
result += `[${String(Math.floor(t / 60000)).padStart(2, '0')}:${String(Math.floor((t % 60000) / 1000)).padStart(2, '0')}.${String(t % 1000).padStart(3, '0')}]${lyric[i][2]}\n`;
}
return result;
}
function extractLinks(text) {
var regex = /https?:\/\/\S+/g;
var matches = text.match(regex);
if (matches) {
return matches[0];
} else {
return '';
}
}
function checkValidLink(link) {
if (link.indexOf("http") === -1 ||
(link.indexOf("music.163.com") === -1 && link.indexOf("163cn.tv") === -1)) {
return false;
}
return true;
}
function extractAndCheckId(text) {
var link = extractLinks(text);
if (checkValidLink(link)) {
return link;
} else {
var idRegex = /\b\d+\b/g;
var ids = text.match(idRegex);
if (ids && ids.length > 0) {
return ids[0];
}
return '';
}
}
// 切换功能区
$('#mode-select').on('change', function() {
if ($(this).val() === 'search') {
$('#search-area').show();
$('#parse-area').hide();
$('#playlist-area').hide();
$('#album-area').hide();
$('#download-area').hide();
$('#song-info').addClass('d-none');
$('#playlist-result').addClass('d-none');
$('#album-result').addClass('d-none');
} else if ($(this).val() === 'parse') {
$('#search-area').hide();
$('#parse-area').show();
$('#playlist-area').hide();
$('#album-area').hide();
$('#download-area').hide();
$('#search-result').addClass('d-none');
$('#playlist-result').addClass('d-none');
$('#album-result').addClass('d-none');
} else if ($(this).val() === 'playlist') {
$('#search-area').hide();
$('#parse-area').hide();
$('#playlist-area').show();
$('#album-area').hide();
$('#download-area').hide();
$('#search-result').addClass('d-none');
$('#song-info').addClass('d-none');
$('#album-result').addClass('d-none');
} else if ($(this).val() === 'album') {
$('#search-area').hide();
$('#parse-area').hide();
$('#playlist-area').hide();
$('#album-area').show();
$('#download-area').hide();
$('#search-result').addClass('d-none');
$('#song-info').addClass('d-none');
$('#playlist-result').addClass('d-none');
$('#album-result').addClass('d-none');
} else if ($(this).val() === 'download') {
$('#search-area').hide();
$('#parse-area').hide();
$('#playlist-area').hide();
$('#album-area').hide();
$('#download-area').show();
$('#search-result').addClass('d-none');
$('#song-info').addClass('d-none');
$('#playlist-result').addClass('d-none');
$('#album-result').addClass('d-none');
} else {
$('#album-area').hide();
$('#download-area').hide();
$('#album-result').addClass('d-none');
}
});
// 搜索功能
$('#search-btn').on('click', function() {
const keywords = $('#search_keywords').val();
const limit = $('#search_limit').val();
if (!keywords) {
alert('请输入搜索关键词');
return;
}
$.ajax({
url: '/Search',
method: 'POST',
data: { keyword: keywords, limit: limit },
dataType: 'json',
success: function(data) {
if (data.status === 200) {
$('#search-list').empty();
data.data.forEach(function(song) {
const item = `<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<img src="${song.picUrl}" alt="cover" style="width:40px;height:40px;object-fit:cover;border-radius:4px;margin-right:10px;">
<strong class='song-title'>${song.name}</strong> - <span>${song.artists}</span> <span class="text-muted">[${song.album}]</span>
</div>
<div>
<button class="btn btn-sm btn-outline-primary select-song me-2" data-id="${song.id}" data-name="${song.name}">解析</button>
<button class="btn btn-sm btn-success download-song" data-id="${song.id}" data-name="${song.name}">下载</button>
</div>
</li>`;
$('#search-list').append(item);
});
$('#search-result').removeClass('d-none');
} else {
$('#search-list').html('<li class="list-group-item">未找到相关歌曲</li>');
$('#search-result').removeClass('d-none');
}
},
error: function() {
$('#search-list').html('<li class="list-group-item">搜索失败,请重试</li>');
$('#search-result').removeClass('d-none');
}
});
});
// 搜索结果点击解析
$(document).on('click', '.select-song', function() {
const songId = $(this).data('id');
$('#song_ids').val(songId);
$('#mode-select').val('parse').trigger('change');
$('html,body').animate({scrollTop: $('#main-form').offset().top}, 300);
});
// 单曲解析
$('#parse-btn').on('click', function() {
const songIds = $('#song_ids').val();
const level = $('#level').val();
if (!songIds) {
alert('请输入歌曲ID或URL');
return;
}
$.post('/Song_V1', { url: songIds, level: level, type:'json' }, function(data) {
if (data.status === 200) {
$('#song_name').text(data.data.name);
$('#artist_names').text(data.data.ar_name);
$('#song_alname').text(data.data.al_name);
$('#song_level').text(data.data.level);
$('#song_size').text(data.data.size);
let processedLyrics = data.data.lyric;
if (data.data.tlyric) {
processedLyrics = lrctran(data.data.lyric, data.data.tlyric);
}
$('#lyric').html(processedLyrics.replace(/\n/g, '<br>'));
$('#song_url').attr('href', data.data.url).text('点击下载');
$('#song-info').removeClass('d-none');
$('#show-big-pic').data('pic', data.data.pic);
new APlayer({
container: document.getElementById('aplayer'),
lrcType: 1,
audio: [{
name: data.data.name,
artist: data.data.ar_name,
url: data.data.url,
cover: data.data.pic,
lrc: processedLyrics
}]
});
} else {
alert(data.data.msg);
}
}, 'json');
});
// 显示大图按钮事件
$(document).on('click', '#show-big-pic', function() {
var picUrl = $(this).data('pic');
$('#big-pic-img').attr('src', picUrl);
var modal = new bootstrap.Modal(document.getElementById('bigPicModal'));
modal.show();
});
// 歌单解析
$('#playlist-btn').on('click', function() {
let pid = $('#playlist_id').val().trim();
if (!pid) {
alert('请输入歌单ID或链接');
return;
}
// 支持直接粘贴歌单链接
const idMatch = pid.match(/playlist\?id=(\d+)/);
if (idMatch) pid = idMatch[1];
$.get('/Playlist', { id: pid }, function(data) {
if (data.status === 200) {
const pl = data.data.playlist;
$('#playlist-cover').attr('src', pl.coverImgUrl);
$('#playlist-name').text(pl.name);
$('#playlist-creator').text('by ' + pl.creator);
$('#playlist-desc').text(pl.description || '');
$('#playlist-count').text(pl.trackCount);
$('#playlist-tracks').empty();
pl.tracks.forEach(function(song, idx) {
const item = `<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<img src="${song.picUrl}" alt="cover" style="width:32px;height:32px;object-fit:cover;border-radius:4px;margin-right:8px;">
<strong class="playlist-title">${idx+1}. ${song.name}</strong> - <span>${song.artists}</span> <span class="text-muted">[${song.album}]</span>
</div>
<div>
<button class="btn btn-sm btn-outline-primary select-song me-2" data-id="${song.id}" data-name="${song.name}">解析</button>
<button class="btn btn-sm btn-success download-song" data-id="${song.id}" data-name="${song.name}">下载</button>
</div>
</li>`;
$('#playlist-tracks').append(item);
});
$('#playlist-result').removeClass('d-none');
} else {
$('#playlist-result').removeClass('d-none');
$('#playlist-tracks').html('<li class="list-group-item">歌单解析失败:'+data.data.msg+'</li>');
}
}, 'json');
});
// 专辑解析
$(document).on('click', '#album-btn', function() {
let aid = $('#album_id').val().trim();
if (!aid) {
alert('请输入专辑ID或链接');
return;
}
// 支持直接粘贴专辑链接
const idMatch = aid.match(/album\?id=(\d+)/);
if (idMatch) aid = idMatch[1];
$.get('/Album', { id: aid }, function(data) {
if (data.status === 200) {
const al = data.data.album;
$('#album-cover').attr('src', al.coverImgUrl);
$('#album-name').text(al.name);
$('#album-artist').text(al.artist);
$('#album-desc').text(al.description || '');
$('#album-count').text(al.songs.length);
$('#album-tracks').empty();
al.songs.forEach(function(song, idx) {
const item = `<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<img src="${song.picUrl}" alt="cover" style="width:32px;height:32px;object-fit:cover;border-radius:4px;margin-right:8px;">
<strong class="playlist-title">${idx+1}. ${song.name}</strong> - <span>${song.artists}</span> <span class="text-muted">[${song.album}]</span>
</div>
<div>
<button class="btn btn-sm btn-outline-primary select-song me-2" data-id="${song.id}" data-name="${song.name}">解析</button>
<button class="btn btn-sm btn-success download-song" data-id="${song.id}" data-name="${song.name}">下载</button>
</div>
</li>`;
$('#album-tracks').append(item);
});
$('#album-result').removeClass('d-none');
} else {
$('#album-result').removeClass('d-none');
$('#album-tracks').html('<li class="list-group-item">专辑解析失败:'+data.data.msg+'</li>');
}
}, 'json');
});
// 音乐下载功能
$('#download-btn').on('click', function() {
const musicId = $('#download_id').val().trim();
const quality = $('#download_quality').val();
if (!musicId) {
alert('请输入音乐ID或URL');
return;
}
// 提取ID支持URL格式
let processedId = musicId;
const idMatch = musicId.match(/song\?id=(\d+)/);
if (idMatch) {
processedId = idMatch[1];
}
// 显示进度条
$('#download-progress').removeClass('d-none');
$('#download-btn').prop('disabled', true).text('下载中...');
// 使用XMLHttpRequest来处理下载并获取响应头
const xhr = new XMLHttpRequest();
xhr.open('POST', '/Download', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.responseType = 'blob';
xhr.onload = function() {
if (xhr.status === 200) {
// 获取自定义响应头
const downloadMessage = xhr.getResponseHeader('X-Download-Message');
const encodedFilename = xhr.getResponseHeader('X-Download-Filename');
const filename = encodedFilename ? decodeURIComponent(encodedFilename) : 'music.flac';
// 创建下载链接
const blob = xhr.response;
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || 'music.flac';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
// 显示完成提示
alert('✅ 音乐文件下载完成!');
console.log(`下载完成: ${filename}`);
if (downloadMessage) {
console.log(`服务器消息: ${downloadMessage}`);
}
} else {
alert('下载失败,请重试');
}
// 重置按钮状态
$('#download-progress').addClass('d-none');
$('#download-btn').prop('disabled', false).text('下载音乐');
};
xhr.onerror = function() {
alert('下载出错,请重试');
$('#download-progress').addClass('d-none');
$('#download-btn').prop('disabled', false).text('下载音乐');
};
// 发送请求
const formData = `id=${encodeURIComponent(processedId)}&quality=${encodeURIComponent(quality)}`;
xhr.send(formData);
});
// 列表中的下载按钮点击事件
// 下载按钮点击跳转到下载功能
$(document).on('click', '.download-song', function() {
const musicId = $(this).data('id');
const songName = $(this).data('name');
if (!musicId) {
alert('无法获取音乐ID');
return;
}
// 填充下载ID并跳转到下载功能区域
$('#download_id').val(musicId);
$('#mode-select').val('download').trigger('change');
$('html,body').animate({scrollTop: $('#main-form').offset().top}, 300);
});
});
</script>
</body>
</html>