From acf704a5e14bbcf2395288a5790bcc255d9fa055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=BD=E6=97=A5=E9=9F=B3=E4=B9=90?= Date: Wed, 24 Sep 2025 14:14:45 +0000 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- add_db.php | 27 ++++ add_db_2.php | 26 ++++ admin_music_upload.php | 305 +++++++++++++++++++++++++++++++++++++++++ api.php | 278 +++++++++++++++++++++++++++++++++++++ 4 files changed, 636 insertions(+) create mode 100644 add_db.php create mode 100644 add_db_2.php create mode 100644 admin_music_upload.php create mode 100644 api.php diff --git a/add_db.php b/add_db.php new file mode 100644 index 0000000..69ceda2 --- /dev/null +++ b/add_db.php @@ -0,0 +1,27 @@ +query("SHOW COLUMNS FROM recommendations LIKE 'status'"); + $columnExists = $result->fetch(); + + if (!$columnExists) { + // 添加状态字段(0:待审核, 1:已同意, 2:已驳回) + $pdo->exec("ALTER TABLE recommendations + ADD COLUMN status TINYINT NOT NULL DEFAULT 0, + ADD COLUMN reviewed_at DATETIME NULL"); + + echo "状态字段添加成功!请刷新页面继续操作。"; + } else { + echo "状态字段已存在,无需重复添加。"; + } + } catch(PDOException $e) { + die("操作失败: " . $e->getMessage()); + } +} else { + die("数据库连接失败,请先检查连接配置。"); +} +?> \ No newline at end of file diff --git a/add_db_2.php b/add_db_2.php new file mode 100644 index 0000000..cda44f6 --- /dev/null +++ b/add_db_2.php @@ -0,0 +1,26 @@ +query("SHOW COLUMNS FROM recommendations LIKE 'user_identifier'"); + $columnExists = $result->fetch(); + + if (!$columnExists) { + // 添加用户标识字段(用于区分不同用户的推荐) + $pdo->exec("ALTER TABLE recommendations + ADD COLUMN user_identifier VARCHAR(255) NOT NULL DEFAULT ''"); + + echo "用户标识字段添加成功!请刷新页面继续操作。"; + } else { + echo "用户标识字段已存在,无需重复添加。"; + } + } catch(PDOException $e) { + die("操作失败: " . $e->getMessage()); + } +} else { + die("数据库连接失败,请先检查连接配置。"); +} +?> \ No newline at end of file diff --git a/admin_music_upload.php b/admin_music_upload.php new file mode 100644 index 0000000..d76b60c --- /dev/null +++ b/admin_music_upload.php @@ -0,0 +1,305 @@ +&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//"; + $output = shell_exec($command); + + if ($output) { + $duration = trim($output); + // 转换为 MM:SS 格式 + list($hours, $minutes, $seconds) = explode(':', $duration); + $seconds = floor((float)$seconds); + if ((int)$hours > 0) { + $minutes = (int)$minutes + (int)$hours * 60; + } + return sprintf('%d:%02d', $minutes, $seconds); + } + } + + // 方法2: 使用getid3库(如果安装了) + if (class_exists('getID3')) { + $getID3 = new getID3; + $fileInfo = $getID3->analyze($file_path); + if (!empty($fileInfo['playtime_seconds'])) { + $seconds = floor($fileInfo['playtime_seconds']); + $minutes = floor($seconds / 60); + $seconds = $seconds % 60; + return sprintf('%d:%02d', $minutes, $seconds); + } + } + + return false; // 无法获取时长 +} + +// 处理审核操作 +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (isset($_POST['approve_id'])) { + $id = $_POST['approve_id']; + try { + // 1. 获取待审核音乐信息(包含BV号和用户输入的时长) + $stmt = $conn->prepare("SELECT * FROM pending_music WHERE id = ?"); + $stmt->execute([$id]); + $music = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($music) { + // 2. 验证音频时长(如果可能) + $duration_mismatch = false; + $actual_duration = getActualAudioDuration($music['file_path']); + + if ($actual_duration && $actual_duration !== $music['duration']) { + // 时长不匹配,设置标志但仍继续处理(只是提醒管理员) + $duration_mismatch = true; + $message .= "注意:用户填写的时长({$music['duration']})与实际音频时长({$actual_duration})不匹配。"; + } + + // 3. 将信息插入正式音乐表(包含BV号字段) + // 如果有实际时长,使用实际时长覆盖用户输入 + $final_duration = $actual_duration ?: $music['duration']; + + $stmt_insert = $conn->prepare("INSERT INTO music + (title, artist, category, description, file_path, duration, upload_time, uploader_name, bvid) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt_insert->execute([ + $music['title'], $music['artist'], $music['category'], + $music['description'], $music['file_path'], $final_duration, + $music['upload_time'], $music['uploader_name'], $music['bvid'] ?? '' + ]); + + // 4. 从待审核表中删除 + $stmt_delete = $conn->prepare("DELETE FROM pending_music WHERE id = ?"); + $stmt_delete->execute([$id]); + + // 构建成功消息 + $base_message = "音乐《" . htmlspecialchars($music['title']) . "》已通过审核!"; + if ($duration_mismatch) { + $message = $base_message . " " . $message; + } else { + $message = $base_message; + } + $message_type = "success"; + } + } catch (PDOException $e) { + $message = "数据库错误: " . $e->getMessage(); + $message_type = "error"; + } + } elseif (isset($_POST['reject_id'])) { + $id = $_POST['reject_id']; + try { + // 获取文件路径用于删除 + $stmt = $conn->prepare("SELECT file_path, title FROM pending_music WHERE id = ?"); + $stmt->execute([$id]); + $music = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($music) { + // 删除服务器上的文件 + if (file_exists($music['file_path'])) { + unlink($music['file_path']); + } + + // 从待审核表中删除记录 + $stmt_delete = $conn->prepare("DELETE FROM pending_music WHERE id = ?"); + $stmt_delete->execute([$id]); + + $message = "音乐《" . htmlspecialchars($music['title']) . "》已驳回并删除。"; + $message_type = "success"; + } + } catch (PDOException $e) { + $message = "数据库错误: " . $e->getMessage(); + $message_type = "error"; + } + } +} + +// 获取所有待审核音乐(包含BV号)并计算实际时长 +try { + $stmt = $conn->query("SELECT * FROM pending_music ORDER BY upload_time DESC"); + $pending_music = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // 为每条音乐获取实际时长并检查是否匹配 + foreach ($pending_music as &$music) { + $actual_duration = getActualAudioDuration($music['file_path']); + $music['actual_duration'] = $actual_duration; + $music['duration_match'] = ($actual_duration === $music['duration']); + } + unset($music); // 解除引用 +} catch (PDOException $e) { + $message = "无法加载待审核列表: " . $e->getMessage(); + $message_type = "error"; + $pending_music = []; +} + +$categories = [ + 'cantonese' => '粤语歌曲', 'mandarin' => '国语歌曲', 'waiyu' => '外语歌曲', + 'classic' => '经典老歌', 'other' => '其他音乐' +]; +?> + + + + + + 管理员审核 - 音乐分享平台 + + + + +
+
+

音乐审核管理

+ 返回首页 +
+ + +
+ + + +

当前没有待审核的音乐。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID标题歌手上传者分类BV号时长信息 上传时间预览操作
+ + + + + + + + +
+ +
+ 用户输入: +
+
+ 实际时长: + + +
+ +
+ + 时长不匹配,通过审核后将使用实际时长 +
+ + +
+ 用户输入: +
+
+ 无法获取实际音频时长 +
+ +
+
+
+ +
+
+ +
+
+ +
+ + + \ No newline at end of file diff --git a/api.php b/api.php new file mode 100644 index 0000000..6b7d501 --- /dev/null +++ b/api.php @@ -0,0 +1,278 @@ +connect_error) { + die(json_encode(array( + "success" => false, + "message" => "数据库连接失败: " . $conn->connect_error + ))); +} + +// 设置数据库连接字符集 +$conn->set_charset("utf8mb4"); + +// 获取硬编码音乐数据 +function getHardcodedMusic() { + $musicPath = __DIR__ . '/data/music.php'; + + // 检查文件是否存在 + if (!file_exists($musicPath)) { + return array( + "success" => false, + "message" => "硬编码音乐文件不存在", + "data" => array() + ); + } + + // 读取硬编码音乐(使用require_once并捕获返回值) + $hardcodedMusic = require_once $musicPath; + + // 验证数据格式 + if (is_array($hardcodedMusic)) { + return array( + "success" => true, + "message" => "成功获取硬编码音乐", + "data" => $hardcodedMusic + ); + } else { + return array( + "success" => false, + "message" => "硬编码音乐格式不正确", + "data" => array() + ); + } +} + +// 从数据库获取音乐 +function getDatabaseMusic($conn) { + $sql = "SELECT id, title, artist, category, mp3, bvid, duration FROM music"; + $result = $conn->query($sql); + + $musicList = array(); + if ($result && $result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $musicList[] = $row; + } + return array( + "success" => true, + "message" => "成功获取数据库音乐", + "data" => $musicList + ); + } else { + return array( + "success" => false, + "message" => "数据库中没有找到音乐数据", + "data" => array() + ); + } +} + +// 获取所有音乐(合并数据库和硬编码) +function getAllMusic($conn) { + // 获取两种来源的音乐 + $dbMusic = getDatabaseMusic($conn); + $hardcodedMusic = getHardcodedMusic(); + + // 合并音乐列表(去重处理) + $allMusic = array(); + $ids = array(); + + // 添加数据库音乐 + foreach ($dbMusic['data'] as $music) { + $id = $music['id']; + if (!in_array($id, $ids)) { + $ids[] = $id; + $allMusic[] = $music; + } + } + + // 添加硬编码音乐 + foreach ($hardcodedMusic['data'] as $music) { + $id = $music['id']; + if (!in_array($id, $ids)) { + $ids[] = $id; + $allMusic[] = $music; + } + } + + return array( + "success" => true, + "message" => "共获取 " . count($allMusic) . " 首音乐(数据库: " . count($dbMusic['data']) . ", 硬编码: " . count($hardcodedMusic['data']) . ")", + "data" => $allMusic, + "sources" => array( + "database" => $dbMusic['success'], + "hardcoded" => $hardcodedMusic['success'] + ) + ); +} + +// 获取音乐标签(合并数据库和硬编码) +function getMusicTags($conn) { + // 获取所有音乐 + $allMusic = getAllMusic($conn); + $tags = array(); + + if ($allMusic['success']) { + foreach ($allMusic['data'] as $music) { + if (!empty($music['category']) && !in_array($music['category'], $tags)) { + $tags[] = $music['category']; + } + } + } + + return array( + "success" => !empty($tags), + "message" => empty($tags) ? "没有找到音乐标签" : "成功获取 " . count($tags) . " 个标签", + "data" => $tags + ); +} + +// 获取音乐地址(同时检查数据库和硬编码) +/** + * 获取音乐地址(同时检查数据库和硬编码)- 修复版 + * 增加了对 SQL 语句准备失败的检查,避免触发 500 错误。 + */ +/** + * 获取音乐的分享播放URL + * 直接返回格式为 shanwogou.cn/audio/play.php?play=音乐id 的链接 + */ +function getMusicUrl($conn) { + // 1. 验证输入的音乐ID + $musicId = $_GET['id'] ?? ''; + if (empty($musicId)) { + return array( + "success" => false, + "message" => "音乐 ID 不能为空" + ); + } + + // 2. 核心逻辑:检查该ID的音乐是否存在于系统中 + // (我们不再返回真实MP3地址,但需要确认音乐ID是有效的) + $musicExists = false; + + // 2.1 先检查数据库 + $sql = "SELECT id FROM music WHERE id = ?"; // 只需检查ID是否存在 + $stmt = $conn->prepare($sql); + + if ($stmt) { // 检查prepare是否成功 + $stmt->bind_param("s", $musicId); + $stmt->execute(); + $stmt->store_result(); + + if ($stmt->num_rows > 0) { + $musicExists = true; + } + $stmt->close(); + } + + // 2.2 如果数据库中不存在,再检查硬编码文件 + if (!$musicExists) { + $hardcodedMusic = getHardcodedMusic(); + if ($hardcodedMusic['success']) { + foreach ($hardcodedMusic['data'] as $music) { + if ((string)$music['id'] === (string)$musicId) { + $musicExists = true; + break; + } + } + } + } + + // 3. 根据检查结果返回响应 + if ($musicExists) { + // 如果音乐存在,生成并返回分享URL + $shareUrl = "https://shanwogou.cn/audio/play.php?play=" . urlencode($musicId); + return array( + "success" => true, + "data" => $shareUrl, + "source" => "share_link" // 标记来源为分享链接 + ); + } else { + // 如果音乐不存在,返回错误信息 + return array( + "success" => false, + "message" => "没有找到该 ID 的音乐" + ); + } +} + +function getAnnouncements($conn) { + // 准备SQL查询,从announcements表中获取所有记录,并按ID倒序排列(最新的在前) + $sql = "SELECT id, nr, time FROM announcements ORDER BY id DESC"; + + // 执行查询 + $result = $conn->query($sql); + + // 初始化一个空数组来存储公告数据 + $announcementList = array(); + + // 检查查询是否成功且有结果 + if ($result && $result->num_rows > 0) { + // 循环遍历所有结果行 + while ($row = $result->fetch_assoc()) { + // 将每一行公告数据添加到数组中 + $announcementList[] = $row; + } + + // 返回成功响应,包含公告数据 + return array( + "success" => true, + "message" => "成功获取 " . count($announcementList) . " 条公告", + "data" => $announcementList + ); + } else { + // 如果查询失败或没有数据,返回失败响应 + return array( + "success" => false, + "message" => "没有找到公告数据或查询失败", + "data" => array() + ); + } +} + +// 处理请求 +// 处理请求 +$action = $_GET['action'] ?? ''; + +switch ($action) { + case 'getAllMusic': + $response = getAllMusic($conn); + break; + case 'getMusicTags': + $response = getMusicTags($conn); + break; + case 'getMusicUrl': + $response = getMusicUrl($conn); + break; + // --- 新增部分 --- + case 'getAnnouncements': + $response = getAnnouncements($conn); + break; + // --- 新增结束 --- + default: + $response = array( + "success" => false, + "message" => "无效的操作,请使用 action=getAllMusic、getMusicTags、getMusicUrl 或 getAnnouncements" + ); +} + +// 输出JSON响应 +echo json_encode($response, JSON_UNESCAPED_UNICODE); + +// 关闭数据库连接 +$conn->close(); +?>