- 今天分享一个汽水音乐解析模板,直接丢进模板子比目录直接使用,喜欢自行部署!
- 定位子比目录 :/wp-content/themes/zibll/pages(创建一个php文件,代码直接丢进去即可!)
模板代码:
<?php
// IP限制相关配置
define('IP_LIMIT_PER_MINUTE', 3); // 每分钟最大请求次数
define('IP_LIMIT_WINDOW', 60); // 时间窗口(秒)
// IP限制函数
function checkIpLimit() {
$ip = $_SERVER['REMOTE_ADDR'];
$cache_key = 'ip_limit_' . $ip;
$current_time = time();
// 获取该IP的请求记录
$requests = get_transient($cache_key);
if (!$requests) {
$requests = array();
}
// 清理过期的请求记录
$requests = array_filter($requests, function($timestamp) use ($current_time) {
return $timestamp > ($current_time - IP_LIMIT_WINDOW);
});
// 计算剩余请求次数
$remaining_requests = IP_LIMIT_PER_MINUTE - count($requests);
// 如果超过限制,计算需要等待的时间
if ($remaining_requests <= 0) {
$oldest_request = min($requests);
$wait_time = $oldest_request + IP_LIMIT_WINDOW - $current_time;
return array(
'allowed' => false,
'remaining' => 0,
'wait_time' => $wait_time
);
}
// 添加新的请求记录
$requests[] = $current_time;
set_transient($cache_key, $requests, IP_LIMIT_WINDOW);
return array(
'allowed' => true,
'remaining' => $remaining_requests - 1
);
}
// 修改代理函数
function proxyAudio($url) {
// 确保在开始处理之前清除所有输出缓冲
while (ob_get_level()) {
ob_end_clean();
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_ENCODING, '');
// 添加更多请求头来模拟浏览器行为
$headers = [
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept: */*',
'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
'Accept-Encoding: gzip, deflate, br',
'Connection: keep-alive',
'Referer: https://music.douyin.com/',
'Origin: https://music.douyin.com',
'Sec-Fetch-Dest: audio',
'Sec-Fetch-Mode: cors',
'Sec-Fetch-Site: cross-site',
'Range: bytes=0-',
'Cache-Control: no-cache',
'Pragma: no-cache'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
error_log("CURL Error for proxyAudio URL {$url}: " . curl_error($ch));
header('HTTP/1.1 500 Internal Server Error');
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['error' => '服务器获取音频失败'], JSON_UNESCAPED_UNICODE);
curl_close($ch);
exit;
}
curl_close($ch);
// 检查HTTP状态码
if ($httpCode !== 200 && $httpCode !== 206) {
header('HTTP/1.1 ' . $httpCode);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['error' => '获取音频文件失败,HTTP状态码: ' . $httpCode], JSON_UNESCAPED_UNICODE);
exit;
}
// 设置响应头
header('Content-Type: ' . ($contentType ? $contentType : 'audio/x-m4a'));
header('Content-Disposition: attachment; filename="music.m4a"');
if ($contentLength) {
header('Content-Length: ' . $contentLength);
}
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// 直接输出响应内容
echo $response;
exit;
}
// 保持原有的解析函数
function getMusicInfo($type = 'json', $url = '')
{
if (strstr($url, 'qishui.douyin.com')) {
$url = headers($url);
preg_match('/track_id=(\d+)/', $url, $match);
} else {
preg_match('/track_id=(\d+)/', $url, $match);
}
if (empty($match[1])) {
throw new Exception('无法获取音乐ID');
}
$curl = curl('https://music.douyin.com/qishui/share/track?track_id=' . $match[1]);
if (empty($curl)) {
throw new Exception('获取音乐信息失败');
}
// 匹配 application/ld+json 数据,获取标题和封面
preg_match('/<script data-react-helmet="true" type="application\/ld\+json">(.*?)<\/script>/s', $curl, $ldJsonMatches);
if (isset($ldJsonMatches[1])) {
$ldJsonData = json_decode(urldecode($ldJsonMatches[1]), true);
$title = $ldJsonData['title'] ?? '';
$cover = isset($ldJsonData['images']) && count($ldJsonData['images']) > 0 ? $ldJsonData['images'][0] : '';
} else {
// 尝试从其他位置获取标题
preg_match('/<title>(.*?)<\/title>/s', $curl, $titleMatch);
$title = isset($titleMatch[1]) ? trim($titleMatch[1]) : '';
// 尝试从其他位置获取封面
preg_match('/<meta property="og:image" content="(.*?)"/s', $curl, $coverMatch);
$cover = isset($coverMatch[1]) ? $coverMatch[1] : '';
}
$jsJsonPattern = '/<script\s+async=""\s+data-script-src="modern-inline">_ROUTER_DATA\s*=\s*({[\s\S]*?});/';
preg_match($jsJsonPattern, $curl, $jsJsonMatches);
if (isset($jsJsonMatches[1])) {
$jsonStr = $jsJsonMatches[1];
$jsonData = json_decode(trim($jsonStr), true);
// 获取音乐URL
$musicUrl = '';
if ($jsonData !== null) {
if (isset($jsonData['loaderData']['track_page']['audioWithLyricsOption']['url'])) {
$musicUrl = $jsonData['loaderData']['track_page']['audioWithLyricsOption']['url'];
} elseif (isset($jsonData['loaderData']['track_page']['audioOption']['url'])) {
$musicUrl = $jsonData['loaderData']['track_page']['audioOption']['url'];
}
}
// 提取歌词
$lrcLyrics = [];
if ($jsonData !== null) {
$lyricsData = $jsonData['loaderData']['track_page']['audioWithLyricsOption']['lyrics'] ??
$jsonData['loaderData']['track_page']['lyrics'] ?? null;
if ($lyricsData && isset($lyricsData['sentences'])) {
$sentences = $lyricsData['sentences'];
foreach ($sentences as $sentence) {
if (isset($sentence['startMs']) && isset($sentence['words'])) {
$startMs = $sentence['startMs'];
$sentenceText = '';
foreach ($sentence['words'] as $word) {
if (isset($word['text'])) {
$sentenceText .= $word['text'];
}
}
$minutes = floor($startMs / 60000);
$seconds = floor(($startMs % 60000) / 1000);
$milliseconds = $startMs % 1000;
$timeTag = sprintf("[%02d:%02d.%03d]", $minutes, $seconds, $milliseconds);
$lrcLyrics[] = $timeTag . $sentenceText;
}
}
}
}
$lyrics = implode("\n", $lrcLyrics);
} else {
$musicUrl = '';
$lyrics = '';
}
// 构建结果数组
$info = array(
'name' => $title ?: '未知歌曲',
'url' => $musicUrl,
'cover' => $cover ?: 'https://p3-pc.douyinpic.com/aweme/1080x1080/aweme-avatar/default_avatar.jpeg',
'lyrics' => $lyrics,
'core' => '抖音汽水音乐解析',
'copyright' => '开心宝:joyb.cc'
);
if (!empty($info['url'])) {
return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} else {
throw new Exception('没有找到相关音乐');
}
}
function curl($url, $data = '', $cookie = '', $headers = [])
{
$con = curl_init((string)$url);
curl_setopt($con, CURLOPT_HEADER, false);
curl_setopt($con, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
curl_setopt($con, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
if (!empty($headers)) {
curl_setopt($con, CURLOPT_HTTPHEADER, $headers);
}
if (!empty($cookie)) {
curl_setopt($con, CURLOPT_COOKIE, $cookie);
}
if (!empty($data)) {
curl_setopt($con, CURLOPT_POST, true);
curl_setopt($con, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($con, CURLOPT_TIMEOUT, 5000);
$result = curl_exec($con);
if ($result === false) {
// curl_error($con) 会提供更详细的错误信息
throw new Exception('CURL错误: ' . curl_error($con));
}
curl_close($con);
return $result;
}
function headers($url)
{
$headers = get_headers($url, 1);
if (isset($headers['Location'])) {
if (is_array($headers['Location'])) {
$url = end($headers['Location']);
} else {
$url = $headers['Location'];
}
}
return $url;
}
// **从这里开始,是请求处理和页面渲染的分支逻辑**
// **这些请求必须在任何HTML输出之前处理**
// 修改AJAX处理部分 - 最优先处理,因为它们不应该输出任何HTML
if(isset($_GET['ajax']) && $_GET['ajax'] == '1') {
header('Content-Type: application/json; charset=utf-8');
// 检查IP限制
$ip_limit_result = checkIpLimit();
if (!$ip_limit_result['allowed']) {
$wait_minutes = ceil($ip_limit_result['wait_time'] / 60);
echo json_encode([
'code' => 429,
'msg' => sprintf('请求过于频繁,请等待 %d 分钟后再试', $wait_minutes),
'wait_time' => $ip_limit_result['wait_time']
], JSON_UNESCAPED_UNICODE);
exit;
}
// 检查用户是否登录
if (!is_user_logged_in()) {
echo json_encode(['code' => 403, 'msg' => '请先登录'], JSON_UNESCAPED_UNICODE);
exit;
}
// 检查用户积分是否足够
$user_id = get_current_user_id();
$user_points = zibpay_get_user_points($user_id);
if ($user_points < 5) {
echo json_encode(['code' => 403, 'msg' => '积分不足,需要5积分'], JSON_UNESCAPED_UNICODE);
exit;
}
$url = isset($_GET['url']) ? $_GET['url'] : '';
$type = isset($_GET['type']) ? $_GET['type'] : 'json';
try {
if ($type !== '' && $url !== '') {
// 解析音乐
$result = json_decode(getMusicInfo($type, $url), true);
if ($result && isset($result['url'])) {
// 扣除积分
$points_data = array(
'order_num' => 'music_parse_' . time(), // 生成订单号
'value' => -5, // 扣除5积分
'type' => '音乐解析', // 类型说明
'desc' => '解析音乐《' . $result['name'] . '》', // 说明
);
zibpay_update_user_points($user_id, $points_data);
echo getMusicInfo($type, $url);
} else {
echo json_encode(['code' => 404, 'msg' => '解析失败,未找到音乐信息'], JSON_UNESCAPED_UNICODE);
}
} else {
echo json_encode(['code' => 404, 'msg' => '请补全参数'], JSON_UNESCAPED_UNICODE);
}
} catch (Exception $e) {
echo json_encode(['code' => 500, 'msg' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
}
exit; // 确保AJAX请求处理后立即退出
}
// 添加音频代理处理 - 优先处理,因为它们不应该输出任何HTML
if(isset($_GET['proxy']) && $_GET['proxy'] == '1') {
$audioUrl = isset($_GET['url']) ? $_GET['url'] : '';
if (!empty($audioUrl)) {
proxyAudio($audioUrl); // proxyAudio 函数内部会处理输出和退出
} else {
header('Content-Type: application/json; charset=utf-8');
header('HTTP/1.1 400 Bad Request');
echo json_encode(['error' => 'Missing audio URL for proxy'], JSON_UNESCAPED_UNICODE);
exit;
}
exit; // 确保代理请求处理后立即退出 (即使proxyAudio内部已经exit, 这里的exit是兜底)
}
// 在PHP部分添加获取积分的处理 - 优先处理
if (isset($_GET['get_points']) && $_GET['get_points'] == '1') {
header('Content-Type: application/json; charset=utf-8');
$user_id = get_current_user_id();
$points = zibpay_get_user_points($user_id);
echo json_encode(['points' => $points]);
exit; // 确保积分请求处理后立即退出
}
// **只有当上述所有特殊请求都没有被处理时,才渲染完整的页面模板**
// 在PHP部分添加登录状态检查
$is_logged_in = is_user_logged_in();
$user_points = $is_logged_in ? zibpay_get_user_points(get_current_user_id()) : 0;
get_header(); // 现在,get_header() 只会在渲染完整页面时调用
?>
<div class="qsmusic-container">
<div class="qsmusic-form">
<h2>汽水音乐解析</h2>
<?php if ($is_logged_in): ?>
<div class="user-info">
<div class="points-card">
<div class="points-header">
<div class="points-icon">🎵</div>
<div class="points-title">音乐解析</div>
</div>
<div class="points-body">
<div class="points-item">
<span class="points-label">当前积分</span>
<span class="points-value" id="currentPoints"><?php echo $user_points; ?></span>
</div>
<div class="points-item">
<span class="points-label">解析消耗</span>
<span class="points-cost">5 积分/次</span>
</div>
</div>
</div>
<div class="parse-form">
<div class="input-wrapper">
<input type="text" id="musicUrl" placeholder="请输入汽水音乐分享链接" class="form-control">
<button onclick="parseMusic()" class="btn btn-primary">
<span class="btn-icon">🎯</span>
<span class="btn-text">开始解析</span>
</button>
</div>
</div>
</div>
<?php else: ?>
<div class="points-notice not-logged-in">
<div class="notice-content">
<i class="fa fa-lock"></i>
<div class="notice-text">
<h4>请先登录后再使用音乐解析功能</h4>
<p>登录后即可使用积分解析音乐</p>
</div>
</div>
<div class="notice-actions">
<a href="<?php echo wp_login_url(get_permalink()); ?>" class="btn btn-primary">立即登录</a>
<a href="<?php echo wp_registration_url(); ?>" class="btn btn-outline">注册账号</a>
</div>
</div>
<!-- 效果预览区 -->
<div class="preview-section">
<h3 class="preview-title">功能预览</h3>
<div class="preview-content">
<div class="preview-image">
<img src="https://joyb.cc/wp-content/uploads/2025/06/20250613164036412-汽水音乐解析演示图-scaled.webp" alt="音乐解析效果预览" />
<div class="preview-overlay">
<p>登录后即可体验完整功能</p>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
<div id="result" class="qsmusic-result" style="display: none;">
<div class="music-info">
<h3 id="title"></h3>
<div class="player-actions">
<a id="downloadLink" href="#" download class="btn btn-secondary">
<span class="download-icon">⬇️</span>
<span class="download-text">下载音乐</span>
<span id="fileSize" class="file-size"></span>
</a>
</div>
<div id="lyrics" class="lyrics"></div>
</div>
</div>
<!-- 修改调试信息区域的HTML结构 -->
<div id="debug" class="debug-container">
<h4>解析详情</h4>
<pre id="debugInfo"></pre>
</div>
</div>
<style>
/* 整个容器的样式 */
.qsmusic-container {
max-width: 800px;
margin: 40px auto;
padding: 40px;
background: #fff;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
min-height: calc(100vh - 200px);
display: flex;
flex-direction: column;
transition: all 0.3s ease;
}
/* 夜间模式样式 */
body.dark-theme .qsmusic-container {
background: #1a1a1a;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
.qsmusic-container .qsmusic-form {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
.qsmusic-container .qsmusic-form h2 {
color: #2c3e50;
margin-bottom: 40px;
font-size: 32px;
font-weight: 600;
transition: color 0.3s ease;
}
body.dark-theme .qsmusic-container .qsmusic-form h2 {
color: #e0e0e0;
}
.qsmusic-container .user-info {
display: flex;
flex-direction: column;
gap: 32px;
}
.qsmusic-container .points-card {
background: linear-gradient(135deg, #6c5ce7, #a8a4e6);
border-radius: 16px;
padding: 30px;
color: white;
box-shadow: 0 4px 15px rgba(108, 92, 231, 0.2);
transition: all 0.3s ease;
}
body.dark-theme .qsmusic-container .points-card {
background: linear-gradient(135deg, #5b4bc4, #8a85d6);
box-shadow: 0 4px 15px rgba(91, 75, 196, 0.3);
}
.qsmusic-container .points-header {
display: flex;
align-items: center;
margin-bottom: 24px;
}
.qsmusic-container .points-icon {
font-size: 32px;
margin-right: 16px;
}
.qsmusic-container .points-title {
font-size: 24px;
font-weight: 500;
}
.qsmusic-container .points-body {
display: flex;
justify-content: space-between;
gap: 24px;
}
.qsmusic-container .points-item {
flex: 1;
text-align: center;
padding: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
backdrop-filter: blur(5px);
}
.qsmusic-container .points-label {
display: block;
font-size: 16px;
opacity: 0.9;
margin-bottom: 8px;
}
.qsmusic-container .points-value {
font-size: 32px;
font-weight: 600;
}
.qsmusic-container .points-cost {
font-size: 28px;
font-weight: 500;
color: #ffd700;
}
.qsmusic-container .parse-form {
background: #f8f9fa;
border-radius: 16px;
padding: 30px;
border: 1px solid #e9ecef;
transition: all 0.3s ease;
}
body.dark-theme .qsmusic-container .parse-form {
background: #2a2a2a;
border-color: #3a3a3a;
}
.qsmusic-container .input-wrapper {
display: flex;
gap: 16px;
margin-bottom: 16px;
}
/* 输入框和按钮样式 */
.qsmusic-container #musicUrl {
flex: 1;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
height: 48px;
box-sizing: border-box;
}
.qsmusic-container #musicUrl:focus {
border-color: #6c5ce7;
outline: none;
box-shadow: 0 0 0 3px rgba(108,92,231,0.1);
}
.qsmusic-container .btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
height: 48px;
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
.qsmusic-container .btn-primary {
background: #6c5ce7;
color: white;
}
.qsmusic-container .btn-primary:hover {
background: #5b4bc4;
transform: translateY(-1px);
}
.qsmusic-container .btn-secondary {
background: #6c757d;
color: white;
}
.qsmusic-container .btn-secondary:hover {
background: #5a6268;
transform: translateY(-1px);
}
.qsmusic-container .btn-icon {
font-size: 18px;
}
.qsmusic-container .form-tips {
display: flex;
align-items: center;
gap: 10px;
color: #6c757d;
font-size: 16px;
margin-top: 16px;
transition: color 0.3s ease;
}
body.dark-theme .qsmusic-container .form-tips {
color: #a0a0a0;
}
.qsmusic-container .tip-icon {
font-size: 20px;
}
.qsmusic-container .music-info {
background: #f8f9fa;
border-radius: 12px;
padding: 20px;
margin-top: 20px;
transition: all 0.3s ease;
}
body.dark-theme .qsmusic-container .music-info {
background: #2a2a2a;
border: 1px solid #3a3a3a;
}
.qsmusic-container .music-info h3 {
color: #2c3e50;
font-size: 20px;
margin-bottom: 16px;
text-align: center;
}
.qsmusic-container .player-actions {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
/* 歌词区域滚动条样式 */
.qsmusic-container .lyrics {
max-height: 300px;
overflow-y: auto;
padding: 16px;
background: white;
border-radius: 8px;
font-size: 14px;
line-height: 1.6;
color: #495057;
transition: all 0.3s ease;
scrollbar-width: thin; /* Firefox */
scrollbar-color: #6c5ce7 #f8f9fa; /* Firefox */
}
/* Webkit浏览器的滚动条样式 */
.qsmusic-container .lyrics::-webkit-scrollbar {
width: 8px;
}
.qsmusic-container .lyrics::-webkit-scrollbar-track {
background: #f8f9fa;
border-radius: 4px;
}
.qsmusic-container .lyrics::-webkit-scrollbar-thumb {
background: #6c5ce7;
border-radius: 4px;
transition: all 0.3s ease;
}
.qsmusic-container .lyrics::-webkit-scrollbar-thumb:hover {
background: #5b4bc4;
}
/* 夜间模式滚动条样式 */
body.dark-theme .qsmusic-container .lyrics {
background: #333;
color: #e0e0e0;
scrollbar-color: #a8a4e6 #2a2a2a; /* Firefox */
}
body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-track {
background: #2a2a2a;
}
body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-thumb {
background: #a8a4e6;
}
body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-thumb:hover {
background: #8a85d6;
}
/* 歌词行样式 */
.qsmusic-container .lyrics div {
padding: 4px 0;
transition: all 0.3s ease;
}
.qsmusic-container .lyrics div:hover {
color: #6c5ce7;
transform: translateX(4px);
}
body.dark-theme .qsmusic-container .lyrics div:hover {
color: #a8a4e6;
}
/* 无歌词提示样式 */
.qsmusic-container .no-lyrics {
text-align: center;
color: #6c757d;
padding: 20px;
font-style: italic;
}
body.dark-theme .qsmusic-container .no-lyrics {
color: #a0a0a0;
}
.qsmusic-container .file-size {
font-size: 0.9em;
opacity: 0.8;
margin-left: 4px;
}
/* 调试信息容器样式 */
.qsmusic-container .debug-container {
display: none;
margin-top: 20px;
padding: 20px;
background: #f8f9fa;
border-radius: 12px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 14px;
line-height: 1.6;
color: #2c3e50;
border: 1px solid #e9ecef;
transition: all 0.3s ease;
}
body.dark-theme .qsmusic-container .debug-container {
background: #1a1a1a;
border-color: #2a2a2a;
color: #e0e0e0;
}
.qsmusic-container .debug-container h4 {
margin: 0 0 15px 0;
color: #2c3e50;
font-size: 16px;
font-weight: 600;
transition: color 0.3s ease;
text-align: center;
position: relative;
padding-bottom: 10px;
}
.qsmusic-container .debug-container h4:after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 2px;
background: #6c5ce7;
border-radius: 2px;
}
body.dark-theme .qsmusic-container .debug-container h4 {
color: #e0e0e0;
}
body.dark-theme .qsmusic-container .debug-container h4:after {
background: #a8a4e6;
}
.qsmusic-container #debugInfo {
margin: 0;
white-space: pre-wrap;
word-break: break-all;
background: #fff;
padding: 15px;
border-radius: 8px;
border: 1px solid #e9ecef;
color: #495057;
transition: all 0.3s ease;
}
body.dark-theme .qsmusic-container #debugInfo {
background: #2a2a2a;
border-color: #3a3a3a;
color: #d0d0d0;
}
/* 调试信息中的URL和状态码样式 */
.qsmusic-container #debugInfo {
font-family: 'Consolas', 'Monaco', monospace;
}
.qsmusic-container #debugInfo a {
color: #6c5ce7;
text-decoration: none;
transition: color 0.3s ease;
}
body.dark-theme .qsmusic-container #debugInfo a {
color: #a8a4e6;
}
.qsmusic-container #debugInfo a:hover {
text-decoration: underline;
}
/* 调试信息中的错误信息样式 */
.qsmusic-container #debugInfo .error {
color: #e74c3c;
font-weight: 500;
}
body.dark-theme .qsmusic-container #debugInfo .error {
color: #ff6b6b;
}
/* 调试信息中的成功信息样式 */
.qsmusic-container #debugInfo .success {
color: #2ecc71;
font-weight: 500;
}
body.dark-theme .qsmusic-container #debugInfo .success {
color: #69db7c;
}
/* 调试信息中的警告信息样式 */
.qsmusic-container #debugInfo .warning {
color: #f1c40f;
font-weight: 500;
}
body.dark-theme .qsmusic-container #debugInfo .warning {
color: #ffd43b;
}
/* 调试信息中的信息样式 */
.qsmusic-container #debugInfo .info {
color: #3498db;
font-weight: 500;
}
body.dark-theme .qsmusic-container #debugInfo .info {
color: #74c0fc;
}
/* 响应式设计 */
@media (max-width: 768px) {
.qsmusic-container {
margin: 20px;
padding: 30px;
min-height: calc(100vh - 100px);
}
body.dark-theme .qsmusic-container {
background: #1a1a1a;
}
.qsmusic-container .login-notice {
padding: 30px 20px;
}
body.dark-theme .qsmusic-container .login-notice {
background: #2a2a2a;
}
.qsmusic-container .notice-icon {
font-size: 40px;
margin-bottom: 20px;
}
.qsmusic-container .notice-content p {
font-size: 16px;
}
.qsmusic-container .notice-desc {
font-size: 14px;
margin: 10px 0 20px !important;
}
.qsmusic-container .login-buttons {
flex-direction: column;
gap: 12px;
}
.qsmusic-container .login-buttons .btn {
width: 100%;
padding: 12px 24px;
}
.qsmusic-container .points-body {
flex-direction: column;
gap: 12px;
}
.qsmusic-container .input-wrapper {
flex-direction: column;
}
.qsmusic-container .btn {
width: 100%;
}
.qsmusic-container .debug-container {
padding: 15px;
font-size: 13px;
}
.qsmusic-container #debugInfo {
padding: 12px;
}
}
/* 效果预览区样式 */
.qsmusic-container .preview-section {
margin-top: 30px;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
transition: all 0.3s ease;
}
.qsmusic-container .preview-title {
text-align: center;
color: #333;
margin-bottom: 20px;
font-size: 1.2em;
position: relative;
padding-bottom: 10px;
}
.qsmusic-container .preview-title:after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 2px;
background: #6c5ce7;
}
.qsmusic-container .preview-content {
padding: 10px;
}
.qsmusic-container .preview-image {
position: relative;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.qsmusic-container .preview-image img {
width: 100%;
height: auto;
display: block;
transition: all 0.3s ease;
}
.qsmusic-container .preview-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: all 0.3s ease;
}
.qsmusic-container .preview-image:hover .preview-overlay {
opacity: 1;
}
.qsmusic-container .preview-overlay p {
color: white;
font-size: 18px;
text-align: center;
padding: 20px;
background: rgba(108,92,231,0.9);
border-radius: 8px;
transform: translateY(20px);
transition: all 0.3s ease;
}
.qsmusic-container .preview-image:hover .preview-overlay p {
transform: translateY(0);
}
/* 夜间模式样式 */
body.dark-theme .qsmusic-container .preview-section {
background: #2a2a2a;
}
body.dark-theme .qsmusic-container .preview-title {
color: #e0e0e0;
}
/* 响应式调整 */
@media (max-width: 768px) {
.qsmusic-container .preview-section {
padding: 15px;
}
.qsmusic-container .preview-overlay p {
font-size: 16px;
padding: 15px;
}
}
</style>
<script>
// 修改获取当前积分的函数
async function getCurrentPoints() {
try {
const response = await fetch(window.location.href + '?get_points=1');
const data = await response.json();
if (data.points !== undefined) {
document.getElementById('currentPoints').textContent = data.points;
}
} catch (error) {
console.error('Error fetching points:', error);
document.getElementById('currentPoints').textContent = '获取失败';
}
}
// 只在登录状态下获取积分
<?php if ($is_logged_in): ?>
document.addEventListener('DOMContentLoaded', getCurrentPoints);
<?php endif; ?>
async function fetchAudio(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const blob = await response.blob();
return {
size: blob.size
};
} catch (error) {
console.error('Error fetching audio:', error);
throw error;
}
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 修改自动提取链接的函数
function extractMusicUrl(text) {
// 匹配抖音/快手分享链接的正则表达式
const urlPattern = /(https?:\/\/[^\s]+)/g;
const matches = text.match(urlPattern);
if (matches) {
// 找到第一个匹配的链接
let url = matches[0];
// 移除链接末尾可能的多余字符
url = url.replace(/[.,;:!?]$/, '');
// 修复可能的URL格式问题
url = url.replace(/qishuidouyincom/g, 'qishui.douyin.com');
// 确保URL格式正确
if (!url.startsWith('http')) {
url = 'https://' + url;
}
return url;
}
return '';
}
// 修改输入框的粘贴事件处理
document.getElementById('musicUrl').addEventListener('paste', function(e) {
// 获取粘贴的文本
const pastedText = (e.clipboardData || window.clipboardData).getData('text');
// 提取链接
const extractedUrl = extractMusicUrl(pastedText);
if (extractedUrl) {
// 阻止默认粘贴行为
e.preventDefault();
// 设置提取后的链接
this.value = extractedUrl;
// 自动触发解析 (如果您不希望粘贴后立即解析,请注释掉此行)
// parseMusic();
}
});
// 修改输入框的输入事件处理
document.getElementById('musicUrl').addEventListener('input', function(e) {
const text = this.value;
// 如果输入框内容包含链接,自动提取
if (text.includes('http') || text.includes('qishui')) {
const extractedUrl = extractMusicUrl(text);
if (extractedUrl && extractedUrl !== text) {
this.value = extractedUrl;
}
}
});
// 修改调试信息显示函数
function updateDebugInfo(message, type = 'info') {
const debugInfo = document.getElementById('debugInfo');
const timestamp = new Date().toLocaleTimeString();
const formattedMessage = `[${timestamp}] ${message}`;
// 根据消息类型添加不同的样式类
const messageElement = document.createElement('div');
messageElement.textContent = formattedMessage;
messageElement.className = type;
debugInfo.appendChild(messageElement);
debugInfo.scrollTop = debugInfo.scrollHeight;
}
// 修改解析函数
function parseMusic() {
const musicUrl = document.getElementById('musicUrl').value.trim();
if (!musicUrl) {
layer.msg('请输入音乐分享链接', {icon: 2});
return;
}
// 如果输入的不是纯链接,尝试提取
if (!musicUrl.startsWith('http')) {
const extractedUrl = extractMusicUrl(musicUrl);
if (extractedUrl) {
document.getElementById('musicUrl').value = extractedUrl;
} else {
layer.msg('无法识别有效的音乐分享链接', {icon: 2});
return;
}
}
// 清空上次解析结果
document.getElementById('title').textContent = '';
document.getElementById('downloadLink').href = '#';
document.getElementById('downloadLink').download = '';
document.getElementById('fileSize').textContent = '';
document.getElementById('lyrics').innerHTML = '';
// 清空调试信息
document.getElementById('debugInfo').innerHTML = '';
// 显示加载状态
document.getElementById('result').style.display = 'none';
document.getElementById('debug').style.display = 'block';
updateDebugInfo('正在解析...', 'info');
// 使用当前页面的完整URL
const currentUrl = window.location.href;
const requestUrl = `${currentUrl}${currentUrl.includes('?') ? '&' : '?'}ajax=1&url=${encodeURIComponent(musicUrl)}&type=json`;
// 显示请求URL
updateDebugInfo(`请求URL: ${requestUrl}`, 'info');
fetch(requestUrl)
.then(response => {
// 显示响应状态
updateDebugInfo(`响应状态: ${response.status} ${response.statusText}`, 'info');
if (!response.ok) {
return response.text().then(text => {
throw new Error(`HTTP error! status: ${response.status}, response: ${text}`);
});
}
return response.json();
})
.then(async data => {
// 显示响应数据
updateDebugInfo(`响应数据: ${JSON.stringify(data, null, 2)}`, 'info');
if (data.code === 403) {
throw new Error(data.msg);
}
if (data.code === 429) {
// 处理请求限制
const waitTime = data.wait_time || 60;
const waitMinutes = Math.ceil(waitTime / 60);
throw new Error(`请求过于频繁,请等待 ${waitMinutes} 分钟后再试`);
}
if (data.url) {
document.getElementById('result').style.display = 'block';
document.getElementById('title').textContent = data.name;
try {
// 获取代理URL
const proxyUrl = `${window.location.href.split('?')[0]}?proxy=1&url=${encodeURIComponent(data.url)}`;
// 显示加载状态
updateDebugInfo('正在获取文件信息...', 'info');
// 设置下载链接
const downloadLink = document.getElementById('downloadLink');
downloadLink.href = proxyUrl;
downloadLink.download = `${data.name || 'music'}.m4a`;
// 获取文件大小
const { size } = await fetchAudio(proxyUrl);
// 显示文件大小
const fileSizeElement = document.getElementById('fileSize');
fileSizeElement.textContent = `(${formatFileSize(size)})`;
// 处理歌词
const lyricsDiv = document.getElementById('lyrics');
if (data.lyrics) {
lyricsDiv.innerHTML = data.lyrics.split('\n').map(line =>
`<div>${line}</div>`
).join('');
} else {
lyricsDiv.innerHTML = '<div class="no-lyrics">暂无歌词</div>';
}
// 更新积分显示
getCurrentPoints();
updateDebugInfo('解析完成', 'success');
} catch (error) {
console.error('Error:', error);
updateDebugInfo(`错误: ${error.message}`, 'error');
layer.msg('获取文件信息失败,请重试', {icon: 2});
}
} else {
throw new Error(data.msg || '解析失败,未找到音乐URL');
}
})
.catch(error => {
console.error('Error:', error);
updateDebugInfo(`错误: ${error.message}`, 'error');
if (error.message.includes('积分不足') || error.message.includes('请先登录')) {
layer.msg(error.message, {icon: 2});
} else if (error.message.includes('请求过于频繁')) {
layer.msg(error.message, {icon: 2, time: 5000});
} else {
layer.msg('解析出错,请查看调试信息', {icon: 2});
}
});
}
</script>
<?php
get_footer();
?>
© 版权声明
文章版权归作者所有,未经允许请勿转载。
暂无评论内容