1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| const axios = require("axios"); const fs = require("fs-extra"); const OSS = require('ali-oss'); const path = require('path'); const emojiRegex = require('emoji-regex'); const config = require("./config.json"); const allLocalData = require("./data.json");
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const getAllData = async (cookie, babyId, since = 0, retries = 3) => { try {
await delay(500);
const response = await axios.get( `https://shiguangxiaowu.cn/events/updates?style=best_12&skip_invisible=true&include_rt=true&since=${since}&baby_id=${babyId}`, { headers: { Cookie: cookie, }, } );
const data = response.data; const lastItem = data.list[data.list.length - 1]; const nextSince = lastItem.updated_at_in_ts;
if (data.next) { const nextPageData = await getAllData(cookie, babyId, nextSince); return data.list.concat(nextPageData); } else { return data.list; } } catch (error) { if (retries > 0) { console.warn(`获取数据失败,正在重试... 剩余重试次数:${retries}`); return getAllData(cookie, babyId, since, retries - 1); } else { console.error(`获取数据失败:${error.message}`); return []; } } };
const extractData = (allData) => { const extractedData = []; allData.forEach((item) => { item?.layout_detail?.forEach((detail) => { if (detail.type === "picture" || detail.type === "video") { const urlKey = detail.type === "picture" ? "picture" : "video_path"; const url = detail[urlKey].replace(/^(?:https?:\/\/)[^/]+\/?/, "");
extractedData.push({ months: item.months, days: item.days, type: detail.type, content: detail.content, [urlKey]: url, }); } }); });
return extractedData; };
const saveDataToJSON = (extractedData) => { fs.writeFileSync("data.json", JSON.stringify(extractedData, null, 2)); };
const getOSSParams = async (cookie) => { const response = await axios.get("https://shiguangxiaowu.cn/moments/new", { params: { force_aliyun: "true", }, headers: { Cookie: cookie, }, });
return response.data; };
const downloadImagesAndVideos = async (items, ossParams, basePath) => { const ossClient = new OSS({ region: 'oss-cn-shenzhen', accessKeyId: ossParams.access_key_id, accessKeySecret: ossParams.access_key_secret, stsToken: ossParams.sts_token, bucket: 'timehut-cn-sz', endpoint: 'https://oss-cn-shenzhen.aliyuncs.com', refreshSTSTokenInterval: 30 * 60 * 1000, refreshSTSToken: async function () { const newOSSParams = await getOSSParams(cookie); return { accessKeyId: newOSSParams.access_key_id, accessKeySecret: newOSSParams.access_key_secret, stsToken: newOSSParams.sts_token }; } }); const total = items.length; for (const [index, item] of items.entries()) { const dirPath = `${basePath}/${item.months}/${item.days}`; await fs.ensureDir(dirPath);
const filePath = `${dirPath}/${item.content ? removeEmojisAndNewlines(item.content) : index}`;
let fileUrl, extension; if (item.type === 'picture') { fileUrl = item.picture; extension = path.extname(fileUrl); } else if (item.type === 'video') { fileUrl = item.video_path; extension = path.extname(fileUrl); }
const localPath = `${filePath}${extension}`;
if (fs.existsSync(localPath)) { console.log(`(${index + 1}/${total}) 文件已存在,跳过下载: ${localPath}`); continue; }
try { const result = await ossClient.get(fileUrl, localPath); console.log(`(${index + 1}/${total}) 下载${item.type === 'picture' ? '图片' : '视频'}成功: ${localPath}`); } catch (error) { console.log(`(${index + 1}/${total}) 下载失败:`, error); } } };
function removeEmojisAndNewlines(text) { const regex = emojiRegex(); return text.replace(regex, '').replace(/[\r\n]+/g, ''); }
(async () => { const cookie = config.cookie; const baby_id = config.baby_id; const basePath = config.basePath; const useLocalData = config.useLocalData;
if (!useLocalData || allLocalData.length === 0) { const allData = await getAllData(cookie, baby_id); const extractedData = extractData(allData); saveDataToJSON(extractedData); }
const data = useLocalData ? allLocalData : extractedData; const ossParams = await getOSSParams(cookie); await downloadImagesAndVideos(data, ossParams, basePath); })();
|