小红书无水印媒体

读取小红书页面内容的图片视频的无水印媒体数据,左侧按钮是解析出链接,显示在页面内,右边蓝色按钮是把链接发送到网页文件下载器,进行下载。评论的图片,只发送到网页下载器下载。

  1. // ==UserScript==
  2. // @name 小红书无水印媒体
  3. // @namespace http://your.namespace.com
  4. // @version 0.2
  5. // @description 读取小红书页面内容的图片视频的无水印媒体数据,左侧按钮是解析出链接,显示在页面内,右边蓝色按钮是把链接发送到网页文件下载器,进行下载。评论的图片,只发送到网页下载器下载。
  6. // @author Your name
  7. // @match https://www.xiaohongshu.com/*
  8. // @icon https://www.xiaohongshu.com/favicon.ico
  9. // ==/UserScript==
  10.  
  11. // 创建按钮元素
  12. var button = document.createElement('button');
  13. button.innerHTML = '按钮';
  14. // 设置按钮样式
  15. button.style.position = 'fixed';
  16. button.style.top = '0';
  17. button.style.left = '0';
  18. button.style.zIndex = '9999';
  19. button.addEventListener('click',function(event){
  20. console.log(unsafeWindow.__INITIAL_STATE__)
  21. })
  22. //将按钮添加到页面的body元素中
  23. document.body.appendChild(button);
  24.  
  25. //目录路径,一定要把单斜杠换成双斜杠
  26. var 文件保存目录='';
  27. //示例 var 服务器地址='http://127.0.0.1:5001/xiaohongshudown';
  28. var 服务器地址='';
  29. var globalJSON = [];
  30. var subJSON = [];
  31. var 页面源码='';
  32. (function (){
  33. var css=`
  34. .author[target="_blank"]{
  35. max-width: 100px;
  36. }
  37. .mianban {
  38. background-color: rgb(140 153 133 / 80%);
  39. border-radius: 5px;
  40. border: 2px solid #bbb;
  41. box-shadow: 0 1px 0 rgb(0 0 0 / 30%), 0 2px 2px -1px rgb(0 0 0 / 50%), 0 1px 0 rgb(255 255 255 / 30%) inset;
  42. z-index: 888;
  43. width: 400px;
  44. overflow-y: scroll;
  45. position: fixed;
  46. left: 25px;
  47. }
  48. .Recordingpanel {
  49. z-index: 999;
  50. width: 350px;
  51. left: 25px;
  52. position: fixed;
  53. overflow-y: scroll;
  54. background-color: rgb(184 168 40 / 80%);
  55. border-radius: 5px;
  56. border: 2px solid #bbb;
  57. box-shadow: 0 1px 0 rgb(0 0 0 / 30%), 0 2px 2px -1px rgb(0 0 0 / 50%), 0 1px 0 rgb(255 255 255 / 30%) inset;
  58. }
  59. .Recordingpanel.hidden {
  60. display: none;
  61. }
  62. .Recordingtext {
  63. padding: 5px 10px;
  64. border-radius: 15px;
  65. margin: 5px 0px;
  66. cursor: pointer;
  67. position: relative;
  68. background: #b1a125;
  69. }
  70. .Recordingtext.error {
  71. background: #b13325;
  72. }
  73. .jilubutton{
  74. left: 0px;
  75. padding: 10px 0px 5px 3px;
  76. border-radius: 0px 5px 5px 0px;
  77. position: fixed;
  78. width: 20px;
  79. height: 50px;
  80. background: #b1a125;
  81. cursor: pointer;
  82. user-select: none;
  83. }
  84. .jilubutton:hover {
  85. background: rgb(203 169 0);
  86. }
  87. .jilubutton:active {
  88. background: rgb(203 103 0); /* 点击时的颜色 */
  89. }
  90. .set-button {
  91. color: #fff;
  92. border-color: #269CE9;
  93. background-color: #269CE9;
  94. border-radius: 5px;
  95. border: 2px solid #bbb;
  96. box-shadow: 0 1px 0 rgb(0 0 0 / 30%), 0 2px 2px -1px rgb(0 0 0 / 50%), 0 1px 0 rgb(255 255 255 / 30%) inset;
  97. }
  98. .set-button:hover::after {
  99. background-color: rgba(255, 255, 255, 0.3) !important;
  100. }
  101. .set-button:hover {
  102. background-color: #70B9E8;
  103. }
  104. .set-button:active {
  105. background: #2db628;
  106. /* position: fixed; */
  107. /* margin-bottom: 9px; */
  108. text-shadow: none;
  109. box-shadow: 10px 10px 10px rgba(0, 0, 0, .3) inset;
  110. }
  111. .yidong{
  112. background: #074836;
  113. }
  114.  
  115. .set-button {
  116. color: #fff !important;
  117. box-shadow:
  118. 0 1px 0 rgb(0 0 0 / 30%),
  119. 1px 2px 2px 0px rgb(247 23 23 / 50%),
  120. 0px -8px 9px rgb(21 133 207 / 100%) inset; /* 只在右边和下边添加内阴影效果 */
  121. }
  122. .custom-button {
  123. position: absolute;
  124. bottom: 0px;
  125. right: -9px;
  126. background: #516447;
  127. width: 20px;
  128. height: 20px;
  129. border-radius: 8px;
  130. cursor: pointer; /* 设置鼠标样式为链接指针 */
  131. overflow: hidden; /* 隐藏伪元素溢出部分 */
  132. }
  133. .custom-button:hover {
  134. background-color: rgb(252 167 4);
  135. }
  136.  
  137. .custom-button:active {
  138. background: rgb(231, 106, 4); /* 点击时的颜色 */
  139. }
  140. .meiti_button{
  141. width: 20px;
  142. height: 20px;
  143. background: #0f77c7;
  144. cursor: pointer;
  145. border-radius: 5px;
  146. }
  147. .meiti_button:hover {
  148. background-color: rgb(252 167 4);
  149. }
  150.  
  151. .meiti_button:active {
  152. background: rgb(231, 106, 4); /* 点击时的颜色 */
  153. }
  154. .pinglun_button{
  155. width: 20px;
  156. height: 20px;
  157. background: rgb(239 199 0);
  158. cursor: pointer;
  159. border-radius: 5px;
  160. }
  161. .pinglun_button:hover {
  162. background: rgb(203 169 0);
  163. }
  164.  
  165. .pinglun_button:active {
  166. background: rgb(203 103 0); /* 点击时的颜色 */
  167. }
  168. [pinglun_button="red"]{
  169. background:red;
  170. }
  171. [pinglun_button="green"]{
  172. background:green;
  173. }
  174. [pinglun_button="brown"]{
  175. background:brown;
  176. }
  177.  
  178. .meiti_send_button{
  179. width: 20px;
  180. height: 20px;
  181. cursor: pointer;
  182. border-radius: 5px;
  183. background:#b1a125;
  184. }
  185. .meiti_send_button:hover {
  186. background: rgb(203 169 0);
  187. }
  188. .meiti_send_button:active {
  189. background: rgb(203 103 0); /* 点击时的颜色 */
  190. }
  191. [meiti_send_button="red"]{
  192. background:red;
  193. }
  194. [meiti_send_button="green"]{
  195. background:green;
  196. }
  197. [meiti_send_button="brown"]{
  198. background:brown;
  199. }
  200. .chaxun{
  201. background:#2a7da54a;
  202. border-radius: 20px;
  203. color: #0068ab ;
  204. }
  205. /*设置按钮*/
  206. .main_button {
  207. position: fixed;
  208. top: 55.5vh;
  209. width: 20px;
  210. height: 50px;
  211. /*background: linear-gradient(to right, , rgba(252, 247, 224, 0.5));*/
  212. background: #FF2442;
  213. cursor: pointer;
  214. z-index: 9999;
  215. border-radius: 0px 5px 5px 0px;
  216. padding: 10px 0px 5px 3px;
  217. user-select: none;
  218. }
  219. /*设置面板*/
  220. .settingPanel {
  221. position: fixed;
  222. top: 55.5vh;
  223. left: 20px;
  224. padding: 10px;
  225. color: #376339;
  226. background: linear-gradient(to right, #DCF0B0, #FCF7E0);
  227. border: 1px solid #000;
  228. z-index: 9999;
  229. display: none;
  230. }
  231.  
  232. .button:hover::after {
  233. border-radius: 5px;
  234. background-color: rgba(255, 255, 255, 0.3) !important;
  235. }
  236.  
  237. .button:hover {
  238. border-radius: 5px;
  239. background-color: #70B9E8;
  240. }
  241.  
  242. .button:active {
  243. border-radius: 5px;
  244. background: #2db628;
  245. /* position: fixed; */
  246. /* margin-bottom: 9px; */
  247. text-shadow: none;
  248. box-shadow: 10px 10px 10px rgba(0, 0, 0, .3) inset;
  249. }
  250. /**/
  251. .floating-btn-sets[data-v-75df8d6e]{
  252. right: 0px;
  253. width: 35px;
  254. }
  255. /*置顶按钮*/
  256. .back-top[data-v-396124b4] {
  257. background: #13b5db00;
  258. width: 35px;
  259. height: 35px;
  260. }
  261. /*置顶按钮*/
  262. .back-top .btn-wrapper[data-v-396124b4] {
  263. background: #49b0ffa1;
  264. }
  265. /*刷新按钮*/
  266. .reload[data-v-053c290a] {
  267. background: #13b5db00;
  268. width: 35px;
  269. height: 35px;
  270. }
  271. /*刷新按钮*/
  272. .reload .btn-wrapper[data-v-053c290a] {
  273. background: #49b0ffa1;
  274. }
  275. `
  276. if(!document.querySelector('.custom')){
  277. var style = document.createElement('style');
  278. style.type = 'text/css';
  279. style.textContent = css;
  280. style.className = "custom";
  281. document.head.appendChild(style);
  282. }
  283.  
  284. })();
  285.  
  286. (function () {
  287. // 创建设置按钮
  288. var settingButton = document.createElement('div');
  289. settingButton.className = 'main_button';
  290. settingButton.innerHTML = '设置';
  291. document.body.appendChild(settingButton);
  292.  
  293. var settingPanel = document.createElement('div');
  294. settingPanel.className='settingPanel';
  295. settingPanel.innerHTML = `
  296. <label for="server">服务器地址:</label>
  297. <br>
  298. <textarea class="server_address" placeholder="http://127.0.0.1:5001/xiaohongshudown" style="width: 200px;resize: none; height: 40px;"></textarea>
  299. <br>
  300. <label for="directory">文件保存目录:</label>
  301. <br>
  302. <textarea class="filedirectory" placeholder="D:\\临时文件\\临时保存" style="width: 200px;resize: none; height: 40px;"></textarea>
  303. <br>
  304. <button id="saveButton" class="button" style="font-weight: bold; color: #333333;cursor:pointer; position: relative;margin: 6px 0px 0px 0px;right: -170px;padding: 4px;">保存</button>
  305.  
  306. `;
  307. document.body.appendChild(settingPanel);
  308. settingPanel.addEventListener('mousedown', function (e) {
  309. dragMenu(settingPanel, e);
  310. });
  311. 按钮绑定(settingButton,settingPanel);
  312. function 按钮绑定(settingButton, settingPanel,) {
  313. settingButton.addEventListener('mousedown', function (e) {
  314. dragMenu(settingButton, e);
  315. });
  316. // 定义一个变量用于保存计时器的 ID
  317. var timerId;
  318. // 给设置按钮绑定鼠标移入事件
  319. settingButton.addEventListener('mouseenter', function () {
  320. // 显示设置面板
  321. settingPanel.style.display = 'block';
  322. // 清除计时器
  323. clearTimeout(timerId);
  324. });
  325. // 给设置面板绑定鼠标移入事件,避免鼠标移出设置按钮后立即隐藏设置面板
  326. settingPanel.addEventListener('mouseenter', function () {
  327. // 清除计时器
  328. clearTimeout(timerId);
  329. });
  330. // 给设置按钮绑定鼠标移出事件
  331. settingButton.addEventListener('mouseleave', function () {
  332. // 开始计时,500 毫秒后隐藏设置面板
  333. timerId = setTimeout(function () {
  334. settingPanel.style.display = 'none';
  335. }, 500);
  336. });
  337. // 给设置面板绑定鼠标移出事件,避免鼠标移入设置面板后立即隐藏设置面板
  338. settingPanel.addEventListener('mouseleave', function () {
  339. // 开始计时,500 毫秒后隐藏设置面板
  340. timerId = setTimeout(function () {
  341. settingPanel.style.display = 'none';
  342. }, 500);
  343. });
  344. // 显示/隐藏设置界面
  345. if (settingButton) {
  346. settingButton.addEventListener('click', function () {
  347. if (settingPanel.style.display === 'none') {
  348. settingPanel.style.display = 'block';
  349. console.log('开始设置');
  350. } else {
  351. settingPanel.style.display = 'none';
  352. }
  353. });
  354. }
  355. }
  356.  
  357. let 服务器地址value = document.querySelector('.server_address');
  358. // 读取缓存服务器地址的值
  359. 服务器地址 = localStorage.getItem('服务器地址');
  360. //如果缓存没有内容就使用默认的数值
  361. if (服务器地址) {
  362. 服务器地址value.value = 服务器地址;
  363. } else {
  364. 服务器地址value.value = 'http://127.0.0.1:5001/xiaohongshudown'; // 默认值
  365. 服务器地址 = 服务器地址value.value;
  366. }
  367.  
  368. let 文件保存目录value = document.querySelector('.filedirectory');
  369. // 读取缓存服务器地址的值
  370. 文件保存目录 = localStorage.getItem('文件保存目录');
  371. //如果缓存没有内容就使用默认的数值
  372. if (文件保存目录) {
  373. 文件保存目录value.value = 文件保存目录;
  374. } else {
  375. 文件保存目录value.value = 'D:\\临时文件\\临时保存'; // 默认值
  376. 文件保存目录 = 文件保存目录value.value;
  377. }
  378. 判断服务器();
  379.  
  380. // 监听保存按钮的点击事件
  381. var saveButton = document.getElementById('saveButton');
  382. saveButton.addEventListener('click', function () {
  383. localStorage.setItem('服务器地址', 服务器地址value.value);
  384. localStorage.setItem('文件保存目录', 文件保存目录value.value);
  385. 文件保存目录 = 文件保存目录value.value
  386.  
  387. });
  388. })();
  389. function 判断服务器(){
  390. if(/^(https?:\/\/)/.test(服务器地址)===false){
  391. showToast('如需要使用外部网页文件下载器,请在源码里填写服务器地址。')
  392. }
  393. }
  394. function 读取页面媒体() {
  395. 'use strict';
  396. var indexValues = [];
  397. // 创建一个数组来保存结果
  398. var resultList = []; // 判断是否存在类名为 '.swiper-wrapper [data-swiper-slide-index]' 的元素
  399. var noteItems = document.querySelectorAll('.swiper-wrapper [data-swiper-slide-index]');
  400. if (noteItems.length != 0) {
  401. // 遍历元素列表
  402. noteItems.forEach(function (element) {
  403. var index = element.getAttribute('data-swiper-slide-index');
  404.  
  405. // 检查该值是否已经存在于数组中
  406. if (indexValues.includes(index)) {
  407. console.log('存在重复值:', index);
  408. return; // 如果存在重复值,停止执行后续命令
  409. }
  410. // 提取 URL 文件名
  411. var backgroundImage = element.style.backgroundImage;
  412.  
  413. if (backgroundImage) {
  414. var matchResult = backgroundImage.match(/([^/]+)$/);
  415.  
  416. if (matchResult) {
  417. var filename = matchResult[0].split('!')[0];
  418. console.log('网址文件名:', filename);
  419. } else {
  420. console.log('未找到匹配的内容');
  421. }
  422. } else {
  423. console.log('backgroundImage 不存在或为空');
  424. }
  425.  
  426. var titleSpanText = document.querySelector('.note-content').textContent.replace(/[<>:"/\\|?*]/g, '');
  427. var username = document.querySelector('.username').textContent.replace(/[<>:"/\\|?*]/g, '');
  428. // 构建结果字符串 用户名-文案-URL文件名
  429. var resultString = username + '----' + titleSpanText + '---' + filename + ".jpeg";
  430. // 将结果字符串添加到结果数组中
  431. var obj = {
  432. filename: resultString,
  433. url: "https://sns-img-hw.xhscdn.net/" + filename
  434. };
  435. resultList.push(obj);
  436. // 记录该值并继续执行后续命令
  437. indexValues.push(index);
  438. });
  439. 创建列表框(resultList);
  440. } else {
  441. // 判断是否存在类名为 '.player-container video' 的元素
  442. noteItems = document.querySelectorAll('.player-container video');
  443. if (noteItems.length !== 0) {
  444. var pageSourceCode = document.documentElement.outerHTML;
  445. var start = pageSourceCode.indexOf('originVideoKey":"') + 'originVideoKey":"'.length;
  446. var end = pageSourceCode.indexOf('"', start);
  447. var filename = pageSourceCode.substring(start, end).replace(/\\u002F/g, "/");
  448. var url ;
  449. if (filename == "" || filename == "rflow: hidden;") {
  450. noteItems.forEach(function (item) {
  451. var 小红书ID=window.location.pathname.split('/').pop()
  452. 访问获取笔记源码(小红书ID);
  453. // url= item.src;
  454. // filename = url.split('/').pop().split('.')[0];
  455. // showToast("当前获取到的视频链接,非原链接,请刷新界面后进入笔记页面。", false)
  456. // console.log(filename);
  457. return;
  458. });
  459. } else {
  460. url = "http://sns-video-bd.xhscdn.com/" + filename
  461. var titleSpanText = document.querySelector('.note-content').textContent.replace(/[<>:"/\\|?*]/g, '');
  462. var username = document.querySelector('.username').textContent.replace(/[<>:"/\\|?*]/g, '');
  463. // 构建结果字符串 用户名-文案-URL文件名
  464. var resultString = username + '----' + titleSpanText + '---' + filename + ".MP4";
  465. // 将结果字符串添加到结果数组中
  466. var obj = {
  467. filename: resultString,
  468. url: url
  469. };
  470. resultList.push(obj);
  471. console.log(filename);
  472. 创建列表框(resultList);
  473. }
  474.  
  475.  
  476. } else {
  477. // 判断是否存在类名为 '.note-item:not([class*=" "])' 的元素
  478. noteItems = document.querySelectorAll('.note-item:not([class*=" "])');
  479. if (noteItems.length != 0) {
  480. // 遍历每个 note-item 元素
  481. noteItems.forEach(function (noteItem, index) {
  482. // 获取 .cover.ld.mask 类名的元素
  483. var coverElement = noteItem.querySelector('.cover.ld.mask');
  484. var backgroundURL = "";
  485. if (coverElement) {
  486. // 获取 background 属性的 URL
  487. backgroundURL = window.getComputedStyle(coverElement).background.match(/url\(["']?([^"']+)["']?\)/)[1];
  488.  
  489. // 检查 coverElement 是否是链接
  490. if (coverElement.tagName === 'A') {
  491. var wenshuid = coverElement.href;
  492. console.log(wenshuid);
  493. } else {
  494. console.log('coverElement 不是一个链接');
  495. }
  496. }
  497.  
  498. // 获取 title 下的 span 文本 文案内容
  499. if (noteItem.querySelector('.title span')) {
  500. var titleSpanText = noteItem.querySelector('.title span').textContent.replace(/[<>:"/\\|?*]/g, '')
  501. }
  502.  
  503. //获取用户名
  504. var username = "";
  505. if (noteItem.querySelector('.active.router-link-exact-active.author span')) {
  506. // 获取 active router-link-exact-active author 下的 span 文本
  507. username = noteItem.querySelector('.active.router-link-exact-active.author span').textContent;
  508. } else {
  509. if (noteItem.querySelector('.author-wrapper span')) {
  510. // 获取 active router-link-exact-active author 下的 span 文本
  511. username = noteItem.querySelector('.author-wrapper span').textContent;
  512. }
  513. }
  514.  
  515. // 提取 URL 文件名
  516. var filename = backgroundURL.substring(backgroundURL.lastIndexOf('/') + 1).split('!')[0];
  517. // 构建结果字符串 用户名-文案-URL文件名
  518. var resultString = username + '----' + titleSpanText + '---' + filename + ".jpeg";
  519. // 将结果字符串添加到结果数组中
  520. var obj = {
  521. filename: resultString,
  522. url: "https://sns-img-hw.xhscdn.net/" + filename
  523. };
  524. resultList.push(obj);
  525. 创建列表框(resultList);
  526. });
  527. }
  528. }
  529. }
  530.  
  531. }
  532.  
  533. function 创建列表框(resultList) {
  534. if (document.querySelector('.mianban')) {
  535. document.querySelector('.mianban').remove();
  536. 延时();
  537. showToast("删除列表成功。", false);
  538. }
  539. // 创建一个选择列表元素
  540. var selectList = document.createElement('div');
  541. // 遍历结果数组,创建选项并添加到选择列表中
  542. resultList.forEach(function (result, index) {
  543. var optionWrapper = document.createElement('div');
  544. optionWrapper.classList.add('optionWrapper');
  545. optionWrapper.style.margin = "5px 10px";
  546. optionWrapper.setAttribute('murl', result.url);
  547. optionWrapper.textContent = result.filename;
  548. optionWrapper.style.cursor = "pointer";
  549. optionWrapper.style.position = "relative";
  550. // 创建带有序号的元素
  551. var indexMarker = document.createElement('div');
  552. indexMarker.style.fontWeight = "bold";
  553. indexMarker.classList.add('indexMarker');
  554. indexMarker.textContent = index + 1 + "、"; // 序号从1开始
  555. optionWrapper.insertBefore(indexMarker, optionWrapper.firstChild);
  556. // 添加鼠标右键点击事件
  557. optionWrapper.addEventListener('contextmenu', function (event) {
  558. // 阻止默认的右键菜单
  559. event.preventDefault();
  560. // 修改组件样式
  561. this.style.backgroundColor = "rgb(0 100 100 / 50%)";
  562. var url = this.getAttribute('murl');
  563. // 复制URL到剪贴板
  564. copyToClipboard(url);
  565. });
  566. // 添加鼠标移入事件
  567. optionWrapper.addEventListener('mouseover', function () {
  568. this.style.backgroundColor = "rgb(0 200 200 / 50%)";
  569. });
  570. // 添加鼠标移出事件
  571. optionWrapper.addEventListener('mouseout', function () {
  572. // 恢复原始背景色
  573. this.style.backgroundColor = "";
  574. });
  575. // optionWrapper.addEventListener('dblclick', function () {
  576. // this.style.backgroundColor = "rgb(140 153 133 / 100%)";
  577. // showToast("开始下载媒体信息", true);
  578. // var url = this.getAttribute('murl');
  579. // var filename = this.textContent;
  580. // // 调用 downloadFile 函数进行下载
  581. // downloadFile(url, filename);
  582. // showToast("请选择保存位置", true)
  583. // });
  584. //原生JS下载代码,
  585. optionWrapper.setAttribute('data', index);
  586. optionWrapper.addEventListener('dblclick', function (event) {
  587. event.preventDefault();
  588. const index=pseudoElement.getAttribute('data');
  589. 下载文件(index);
  590. });
  591. //创建伪元素
  592. var pseudoElement = document.createElement('div');
  593. pseudoElement.className="custom-button"
  594. pseudoElement.setAttribute('data', index);
  595. pseudoElement.addEventListener('click', function () {
  596. const index=pseudoElement.getAttribute('data');
  597. 下载文件(index);
  598. });
  599. optionWrapper.appendChild(pseudoElement);
  600. selectList.appendChild(optionWrapper);
  601. });
  602. // 添加选择列表到 body 元素
  603. var mianbanbox = document.createElement('div');
  604. var linkWrappers = document.querySelectorAll('.side-bar .link-wrapper:not([class*=" "])'); // 选择所有class为link-wrapper的元素
  605. var top = "30%";
  606. linkWrappers.forEach(function (element) {
  607.  
  608. if (element.textContent.trim() === "我") { // 检查元素的文本内容是否为"我"
  609. var rect = element.getBoundingClientRect();
  610. top = rect.top + element.clientHeight + 10 + "px";
  611. console.log(element.textContent.trim())
  612. }
  613. });
  614. mianbanbox.className = "mianban";
  615. console.log(top);
  616. mianbanbox.style.top = top;
  617.  
  618. // 检查是否存在 .side-bar .information-wrapper 元素
  619. var informationWrapper = document.querySelector('.side-bar .information-wrapper:not([class*=" "])');
  620. if (informationWrapper) {
  621. // 如果 .side-bar .information-wrapper 存在,设置 mianbanbox 的高度为该元素顶部到页面顶部的距离
  622. var topOffset = informationWrapper.getBoundingClientRect().top;
  623. mianbanbox.style.height = parseFloat(topOffset) - parseFloat(top) + "px";
  624. console.log(parseFloat(topOffset) - parseFloat(top) + "px")
  625. } else {
  626. // 如果 .side-bar .information-wrapper 不存在,设置 mianbanbox 的高度为 580px
  627. mianbanbox.style.height = "580px";
  628. }
  629.  
  630. // if (document.querySelector('div.side-bar:not([class*=" "])').clientWidth + 24 < 490) {
  631. // mianbanbox.style.overflowX = 'scroll'; // 设置垂直滚动条
  632. // }
  633.  
  634. mianbanbox.appendChild(selectList);
  635. document.querySelector('body').appendChild(mianbanbox);
  636. mianbanbox.addEventListener('mousedown', function (e) {
  637. dragMenu(mianbanbox, e);
  638. });
  639. mianbanbox.addEventListener('scroll', function (event) {
  640. event.preventDefault();
  641. });
  642. function 下载文件(index){
  643. const wenjian=document.querySelectorAll(".optionWrapper")[index];
  644. wenjian.style.backgroundColor = "rgb(140 153 133 / 100%)";
  645. showToast("开始下载媒体信息", true)
  646. var url = wenjian.getAttribute('murl');
  647. var filename = wenjian.textContent;
  648. var xhr = new XMLHttpRequest();
  649. xhr.responseType = 'blob';
  650. xhr.onload = function () {
  651. showToast("文件预下载完成了", true)
  652. var a = document.createElement('a');
  653. a.href = window.URL.createObjectURL(xhr.response);
  654. a.download = filename;
  655. a.style.display = 'none';
  656. document.body.appendChild(a);
  657. showToast("请选择保存位置,并保存文件", true)
  658. a.click();
  659. window.URL.revokeObjectURL(a.href);
  660. document.body.removeChild(a);
  661. };
  662. xhr.open('GET', url);
  663. xhr.send();
  664. return false;
  665. }
  666. }
  667.  
  668. // var 远程下载记录 = localStorage.getItem('远程下载记录');
  669. // //如果缓存没有内容就使用默认的数值
  670. // if (远程下载记录) {
  671. // 远程下载记录 = JSON.parse(远程下载记录)
  672. // for (let index = 0; index < 远程下载记录.length; index++) {
  673.  
  674. // 创建下载记录列表框(远程下载记录[index].记录)
  675. // }
  676. // } else {
  677. // var jsonString = '[]';
  678. // 远程下载记录 = JSON.parse(jsonString);
  679.  
  680. // }
  681. var jsonString = '[]';
  682. var 远程下载记录 = JSON.parse(jsonString);
  683. 创建下载记录列表框("")
  684.  
  685. function 创建下载记录列表框(content, 添加,异常) {
  686. if (!document.querySelector('.Recordingpanel')) {
  687. var linkWrappers = document.querySelectorAll('.side-bar .link-wrapper:not([class*=" "])'); // 选择所有class为link-wrapper的元素
  688. var top = "30%";
  689. linkWrappers.forEach(function (element) {
  690. if (element.textContent.trim() === "我") { // 检查元素的文本内容是否为"我"
  691. var rect = element.getBoundingClientRect();
  692. top = rect.top + element.clientHeight + 10 + "px";
  693. }
  694. });
  695. var parent = document.createElement('div');
  696. parent.className = 'Recordingpanel hidden';
  697. parent.style.top = top;
  698. parent.addEventListener('mousedown', function (e) {
  699. dragMenu(parent, e);
  700. });
  701. var informationWrapper = document.querySelector('.side-bar .information-wrapper:not([class*=" "])');
  702. if (informationWrapper) {
  703. // 如果 .side-bar .information-wrapper 存在,设置 mianbanbox 的高度为该元素顶部到页面顶部的距离
  704. var topOffset = informationWrapper.getBoundingClientRect().top;
  705. parent.style.height = parseFloat(topOffset) - parseFloat(top) + "px";
  706. } else {
  707. // 如果 .side-bar .information-wrapper 不存在,设置 mianbanbox 的高度为 580px
  708. parent.style.height = "580px";
  709. }
  710. parent.addEventListener('scroll', function (event) {
  711. event.preventDefault();
  712. if (parent.scrollTop === 0) {
  713. document.querySelector('.Recordingtext').style.background = '#5ab125'
  714. } else {
  715. console.log(parent.scrollHeight , parent.scrollTop);
  716. if (parent.scrollHeight - parent.scrollTop === parent.clientHeight) {
  717. let Recordingtext = document.querySelectorAll('.Recordingtext')
  718. Recordingtext[Recordingtext.length - 1].style.background = '#7f7313'
  719. }
  720.  
  721. }
  722.  
  723. });
  724. document.querySelector('body').appendChild(parent);
  725. var jilubutton = document.createElement('div');
  726. document.querySelector('body').appendChild(jilubutton);
  727. jilubutton.className = "jilubutton";
  728. let jilubutton_top = (document.querySelector('.main_button')?.getBoundingClientRect()?.top - jilubutton?.getBoundingClientRect()?.height - 10)
  729. if (jilubutton_top != 'NAN') {
  730. jilubutton.style.top = jilubutton_top + 'px'
  731. }
  732. jilubutton.style.top = + 'px';
  733. jilubutton.textContent = "记录";
  734. jilubutton.addEventListener('click', function () {
  735. // 恢复原始背景色
  736. if (document.querySelector('.Recordingpanel.hidden')) {
  737. parent.classList.remove('hidden');
  738. jilubutton.textContent = "关闭";
  739. } else {
  740. parent.classList.add('hidden');
  741. jilubutton.textContent = "记录";
  742. }
  743. });
  744. }
  745. if (content) {
  746. var record_content = document.createElement('div');
  747. record_content.classList.add('Recordingtext');
  748. if(异常){
  749. record_content.classList.add('error');
  750. }
  751. record_content.textContent = content;
  752. var Recordingpanel = document.querySelector('.Recordingpanel')
  753. Recordingpanel.appendChild(record_content)
  754. record_content.addEventListener('mouseover', function (event) {
  755. event.stopPropagation();
  756. var str = record_content.textContent;
  757. var 小红书ID = str.match(/\b[A-Fa-f0-9]{16,}\b/g)?.[0];
  758. if (小红书ID) {
  759. // 获取所有类名为 "title" 的元素
  760. var elements = document.querySelectorAll('.title[href]');
  761. // 遍历这些元素,检查它们的 href 属性
  762. for (var i = 0; i < elements.length; i++) {
  763. if (elements[i].href.includes(小红书ID)) {
  764. elements[i].parentElement?.classList.add('chaxun')
  765. break;
  766. // 如果需要在找到匹配元素后执行其他操作,可以在这里添加代码
  767. }
  768. }
  769. elements = document.querySelectorAll('.cover.ld.mask[href]');
  770. // 遍历这些元素,检查它们的 href 属性
  771. for (var j = 0; j < elements.length; j++) {
  772. if (elements[j].href.includes(小红书ID)) {
  773. elements[j].parentElement?.querySelector('.footer').classList.add('chaxun')
  774. break;
  775. // 如果需要在找到匹配元素后执行其他操作,可以在这里添加代码
  776. }
  777. }
  778. // //这是笔记详情页面
  779. // var script = document.querySelectorAll('script');
  780. // for (let index = 0; index < script.length; index++) {
  781. // if (script[index].textContent.includes(小红书ID)) {
  782. // document.querySelector('.note-content').classList.add('chaxun');
  783. // break;
  784. // }
  785.  
  786. var content = document.querySelectorAll('meta[content]');
  787. for (let index = 0; index < content.length; index++) {
  788. if (content[index].getAttribute('content').includes(小红书ID)) {
  789. document.querySelector('.note-content').classList.add('chaxun');
  790. break;
  791. }
  792. }
  793. var comment_item = document.querySelectorAll('.comment-item');
  794. for (let index = 0; index < comment_item.length; index++) {
  795. if (comment_item[index].id.includes(小红书ID)) {
  796. comment_item[index].classList.add('chaxun');
  797. break;
  798. }
  799. }
  800. }
  801. // 禁止父元素移动的代码
  802. // parent.style.pointerEvents = 'none';
  803. });
  804. record_content.addEventListener('mouseout', function (event) {
  805. event.stopPropagation();
  806. document.querySelector('.chaxun')?.classList?.remove('chaxun');
  807. // 启用父元素移动的代码
  808. // parent.style.pointerEvents = 'auto';
  809. });
  810. if (添加) {
  811. let json = {
  812. 记录: content,
  813. };
  814. 远程下载记录.push(json)
  815. // localStorage.setItem('远程下载记录', JSON.stringify(远程下载记录));
  816. }
  817.  
  818. }
  819. }
  820.  
  821. zhushezhi();
  822. function zhushezhi() {
  823. var div3 = document.createElement('div');
  824. div3.style.fontSize='15px';
  825. div3.style.padding = "7px 10px 0px 10px";
  826. div3.style.zIndex = "999";
  827. div3.style.width = "70px";
  828. div3.style.height = "33px";
  829. div3.style.position = "fixed";
  830. div3.style.cursor = "pointer";
  831.  
  832. div3.style.userSelect = "none";
  833. div3.textContent = "取图片";
  834. div3.className = "set-button";
  835. document.querySelector('body').appendChild(div3);
  836. var top = null;
  837. var left = null;
  838. var gao = document.querySelector('#link-guide')
  839. if (gao) {
  840. var rect = gao.getBoundingClientRect();
  841. top = rect.top - 4 + "px";
  842. left = rect.left + 2 + rect.width + "px";
  843. }
  844. div3.style.top = top;
  845. div3.style.left = left;
  846. div3.addEventListener('click', function () {
  847. console.log('执行打印命令');
  848. if (document.querySelector('.mianban')) {
  849. document.querySelector('.mianban').remove();
  850. showToast("删除列表成功。", false);
  851. }
  852. 读取页面媒体();
  853. showToast("读取页面内小红书媒体信息完成,获取媒体数:" + document.querySelectorAll(".optionWrapper").length, false);
  854. });
  855. div3.addEventListener('contextmenu', function (event) {
  856. event.preventDefault(); // 阻止默认右键菜单
  857. if (document.querySelector('.mianban')) {
  858. document.querySelector('.mianban').remove();
  859. 延时();
  860. showToast("删除列表成功。", false);
  861. }
  862. });
  863.  
  864. }
  865.  
  866. function 延时() {
  867. var count = 0;
  868. var intervalId = setInterval(function () {
  869. var a = 1;
  870. console.log(a);
  871. count++;
  872. if (count === 5) {
  873. clearInterval(intervalId);
  874. }
  875. }, 1000);
  876. }
  877.  
  878.  
  879. //页面元素监测,判断小红书笔记列表是否出现
  880. (function () {
  881. // 创建一个 MutationObserver 实例
  882. var observer = new MutationObserver(function (mutations) {
  883. mutations.forEach(function (mutation) {
  884. // 检查每个变化的类型
  885. if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
  886. // 循环遍历添加的节点
  887. mutation.addedNodes.forEach(function (addedNode) {
  888. // 检查添加的节点是否为目标元素
  889. if (addedNode.classList) {
  890. const authorWrapperElements = addedNode.querySelectorAll('.footer .author-wrapper');
  891. if (authorWrapperElements.length > 0) {
  892. 小红书媒体(authorWrapperElements);
  893. } else {
  894. const authorWrapperElements = addedNode.querySelectorAll('[data-v-ed4befca ][class="author-wrapper"]');
  895. if (authorWrapperElements.length > 0) {
  896. 评论媒体(authorWrapperElements);
  897. } else {
  898. const authorWrapperElements = addedNode.querySelectorAll('.right .author-wrapper');
  899. if (authorWrapperElements.length > 0) {
  900. 评论媒体(authorWrapperElements);
  901. } else {
  902. const interact_container = addedNode.querySelectorAll('.interact-container');
  903. if (interact_container.length > 0) {
  904. 评论框(interact_container);
  905. } else {
  906. const bottom_channel = addedNode.querySelector('.bottom-channel[href="https://creator.xiaohongshu.com/publish/publish?source=official"]');
  907. if (bottom_channel) {
  908. bottom_channel.parentElement.remove();
  909. }
  910. }
  911. }
  912. }
  913. }
  914. }
  915. });
  916. }
  917. });
  918. });
  919. // 开始观察父节点下的变化
  920. observer.observe(document.body, { childList: true, subtree: true });
  921. })();
  922.  
  923. function 访问获取笔记源码(小红书ID, 类型, 按钮) {
  924. get("https://www.xiaohongshu.com/explore/" + 小红书ID + "?exSource=", '', function (content) {
  925. let initialStateText = 取源码JSON文本(content);
  926. if(!initialStateText){
  927. showToast(小红书ID+'--读取页面该笔记源码失败', false);
  928. return;
  929. }
  930. 笔记源码分析(initialStateText,类型,按钮);
  931. });
  932. }
  933. function 取源码JSON文本(content) {
  934. var regex = /window\.__INITIAL_STATE__=(.*?)(?=<\/script>)/s;
  935. var match = regex.exec(content);
  936. if (match && match.length >= 2) {
  937. let initialStateText = match[1];
  938. // 现在 initialStateText 中存储了 window.__INITIAL_STATE__ 和 </script> 之间的内容
  939. initialStateText = initialStateText.replace(/:undefined/g, ':"undefined"');
  940. return initialStateText;
  941. }
  942. }
  943. // 请求函数,接受url和回调函数作为参数,callback为响应文本
  944. function get(url, post, callback) {
  945. var xhr = new XMLHttpRequest();
  946. xhr.open(post ? 'POST' : 'GET', url, false);// 第三个参数设置为false表示同步请求
  947. xhr.withCredentials = true;
  948. xhr.onreadystatechange = function () {
  949. if (xhr.readyState === 4) {
  950. if (xhr.status === 200) {
  951. callback(xhr.responseText);
  952. } else if (xhr.status === 404) {
  953. showToast("资源未找到");
  954. } else if (xhr.status === 500) {
  955. showToast("服务器内部错误");
  956. } else if (xhr.status === 0) {
  957. showToast("连接错误");
  958. } else {
  959. showToast("网络错误或其他错误");
  960. }
  961. }
  962. };
  963. if (post) {
  964. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  965. xhr.send(post);
  966. } else {
  967. xhr.send();
  968. }
  969. }
  970. // fetch('https://m.v.qq.com/x/m/play?cid=mcv8hkc8zk8lnov',{
  971. // credentials: 'include' // 包含cookie信息
  972. // })
  973. // .then(response => response.text())
  974. // .then(data => {
  975. // // 打印元素的文本内容
  976. // doc=元素转DOM对象(data)
  977. // console.log(doc.querySelector('body'))
  978. // })
  979. // .catch(error => console.error(error));
  980.  
  981. // function 元素转DOM对象(data){
  982. // let htmlString = data;
  983. // // 创建一个 DOMParser 实例
  984. // let parser = new DOMParser();
  985. // // 使用 DOMParser 的 parseFromString 方法将 HTML 文本解析为 DOM 对象
  986. // return parser.parseFromString(htmlString, 'text/html');
  987. // }
  988. function 笔记源码分析(initialStateText, 类型, 按钮) {
  989. // 然后再进行 JSON 解析
  990.  
  991. var initialStateJSON = JSON.parse(initialStateText);
  992. // 从 JSON 对象中提取特定路径的内容
  993. var 小红书ID, 用户名, 用户id, 文件名ID, title, desc, time, 时间, currentDate, height, imageurl, videourl, 文件名, 文案, 文件类型, url, returnjson, dfturl, prvurl, 地址;
  994. var resultList = [];
  995. // 赋值操作
  996. 小红书ID = initialStateJSON.note?.firstNoteId;
  997. if(!小红书ID){
  998. 小红书ID = initialStateJSON.note?.firstNoteId?._rawValue;
  999. }
  1000. 用户名 = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.user?.nickname;
  1001. 用户id = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.user?.userId;
  1002. 文件名ID = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.video?.consumer?.originVideoKey;
  1003. title = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.title;
  1004. desc = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.desc;
  1005. time = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.time;
  1006. 地址 = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.ipLocation;
  1007. 文案 = title + desc;
  1008. 文案 = 文案.length > 110 ? 文案.substring(0, 110) : 文案;
  1009. currentDate = new Date();
  1010. 时间 = currentDate.toISOString().replace(/[-T:Z.]/g, '').slice(0, 14).replace(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, '\$1-\$2-\$3 \$4\$5\$6');
  1011. 文件名 = 用户名 + "----" + 用户id + "----" + 文案 + "----" + 小红书ID + "----" + 时间 + ' ' + 地址
  1012. if (文件名ID != undefined) {
  1013. 文件名 = 文件名 + "(" + 1 + ").mp4";
  1014. videourl = "http://sns-video-bd.xhscdn.com/" + 文件名ID
  1015. if (类型 === 1) {
  1016. 文件类型 = "mp4"
  1017. const json = JSON数据(videourl, 文件名ID, 文案, 用户名, 用户id, 文件保存目录, 文件名.replace(/[\\/:*?"<>|,;#%]/g, ''), 文件类型, 小红书ID, '', '');
  1018. 视频下载(json, 0, 按钮)
  1019. } else {
  1020. const obj = {
  1021. filename: 文件名,
  1022. url: videourl
  1023. };
  1024. resultList.push(obj);
  1025. 创建列表框(resultList);
  1026. showToast("读取页面内小红书媒体信息完成,获取视频数:" + document.querySelectorAll(".optionWrapper").length, true);
  1027. }
  1028. } else {
  1029. var arrayLength = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.imageList.length;
  1030. if (arrayLength != 0) {
  1031. for (var i = 0; i < arrayLength; i++) {
  1032. var image = initialStateJSON.note?.noteDetailMap[小红书ID]?.note?.imageList[i];
  1033. 文件名ID = image.fileId;
  1034. if (文件名ID === "") {
  1035. prvurl = image?.infoList[0]?.url
  1036. dfturl = image?.infoList[1]?.url
  1037. 文件名ID = dfturl.substring(dfturl.lastIndexOf("/") + 1, dfturl.lastIndexOf("!"));
  1038. dfturl = image?.infoList[0]?.url
  1039. //( /\/([a-z0-9]+)!/i)
  1040. }
  1041. height = image.height;
  1042. const 新文件名 = 文件名 + "(" + (i + 1) + ").jpeg";
  1043. imageurl = "http://ci.xiaohongshu.com/" + 文件名ID + "?imageView2/2/w/format/png";
  1044. if (类型 === 1) {
  1045. 文件类型 = "webp"
  1046. const json = JSON数据(imageurl, 文件名ID, 文案, 用户名, 用户id, 文件保存目录, 新文件名.replace(/[\\/:*?"<>|,;#%]/g, ''), 文件类型, 小红书ID, prvurl, dfturl);
  1047. 图片下载(json, i, 按钮);
  1048.  
  1049. } else {
  1050. const obj = {
  1051. filename: 文件名,
  1052. url: imageurl
  1053. };
  1054. resultList.push(obj);
  1055. }
  1056. }
  1057. if (类型 === 1) {
  1058. console.log("发起下载完成")
  1059. } else {
  1060. 创建列表框(resultList);
  1061. showToast("读取页面内小红书媒体信息完成,获取图片数:" + document.querySelectorAll(".optionWrapper").length, true);
  1062. }
  1063. }
  1064. }
  1065. }
  1066. function 视频下载(post, index, 按钮) {
  1067. let 下载情况='';
  1068. let 正常=false;
  1069. let 异常 = false;
  1070. var xhr = new XMLHttpRequest();
  1071. xhr.open('POST', 服务器地址, true);
  1072. xhr.withCredentials = true;
  1073. xhr.onreadystatechange = function () {
  1074. if (xhr.readyState === 4) {
  1075. if (xhr.status === 200) {
  1076. let returnjson = JSON.parse(xhr.responseText)
  1077. if (returnjson.下载.下载状态 === "下载完毕") {
  1078. 按钮.setAttribute('meiti_send_button', 'green')
  1079. 异常 = false;
  1080. } else {
  1081. 按钮.setAttribute('meiti_send_button', 'brown')
  1082. 异常 = true;
  1083. }
  1084. 下载情况 = '视频:' + returnjson.用户名 + '--' + returnjson.文案.substring(0, 10) + '--' + returnjson.小红书ID + '--' + returnjson.下载.下载状态;
  1085. console.log(xhr.responseText)
  1086. 正常 = true;
  1087. 创建下载记录列表框(下载情况, true, 异常);
  1088. } else if (xhr.status === 404) {
  1089. 下载情况 = '视频:网络状态{' + xhr.status + ",资源未找到";
  1090. } else if (xhr.status === 500) {
  1091. 下载情况 = '视频:网络状态{' + xhr.status + ",服务器内部错误";
  1092. } else {
  1093. 下载情况 = '视频:网络状态{' + xhr.status + ",网络错误或其他错误";
  1094. }
  1095. if (!正常) {
  1096. 按钮.setAttribute('meiti_send_button', 'brown')
  1097. 判断服务器();
  1098. }
  1099. showToast(下载情况, 正常);
  1100. }
  1101. };
  1102. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  1103. xhr.send(post);
  1104. }
  1105. function 图片下载(post, index, 按钮) {
  1106. var 下载情况='';
  1107. let 正常=false;
  1108. let 异常 = false;
  1109. var xhr = new XMLHttpRequest();
  1110. xhr.open('POST', 服务器地址, true);
  1111. xhr.withCredentials = true;
  1112. xhr.onreadystatechange = function () {
  1113. if (xhr.readyState === 4) {
  1114. if (xhr.status === 200) {
  1115. let returnjson = JSON.parse(xhr.responseText)
  1116. if (returnjson.下载.下载状态 === "下载完毕") {
  1117. 按钮.setAttribute('meiti_send_button', 'green')
  1118. 异常 = false;
  1119. } else {
  1120. 按钮.setAttribute('meiti_send_button', 'brown')
  1121. 异常 = true;
  1122. }
  1123. 正常 = true;
  1124. 下载情况 = '图片(' + (index + 1) + ')' + returnjson.用户名 + '--' + returnjson.文案.substring(0, 10) + '--' + returnjson.小红书ID + returnjson.下载.下载状态;
  1125. console.log(xhr.responseText)
  1126. 创建下载记录列表框(下载情况, true,异常);
  1127. } else {
  1128. if (xhr.status === 404) {
  1129. 下载情况 = '图片(' + (index + 1) + ')--网络状态{' + xhr.status + '},资源未找到\n';
  1130. } else {
  1131. if (xhr.status === 500) {
  1132. 下载情况 = '图片(' + (index + 1) + ')--网络状态{' + xhr.status + ',服务器内部错误\n';
  1133. } else {
  1134. 下载情况 = '图片(' + (index + 1) + ')--网络状态{' + xhr.status + ',网络错误或其他错误\n';
  1135. }
  1136. }
  1137. }
  1138. if (!正常) {
  1139. 按钮.setAttribute('meiti_send_button', 'brown')
  1140. 判断服务器();
  1141. }
  1142. showToast(下载情况, true);
  1143.  
  1144. }
  1145. };
  1146. xhr.onerror = function () {
  1147. showToast('发生网络错误');
  1148. };
  1149. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  1150. xhr.send(post);
  1151. }
  1152. function 评论图片下载(post, index, 按钮) {
  1153. let 下载情况='';
  1154. let 正常=false;
  1155. let 异常 = false;
  1156. var xhr = new XMLHttpRequest();
  1157. xhr.open('POST', 服务器地址, true);
  1158. xhr.withCredentials = true;
  1159. xhr.onreadystatechange = function () {
  1160. if (xhr.readyState === 4) {
  1161. if (xhr.status === 200) {
  1162. let returnjson = JSON.parse(xhr.responseText)
  1163. if (returnjson.下载.下载状态 === "下载完毕") {
  1164. 按钮.setAttribute('pinglun_button', 'green')
  1165. 异常 = false;
  1166. } else {
  1167. 按钮.setAttribute('pinglun_button', 'brown')
  1168. 异常 = true;
  1169. }
  1170. 下载情况 = '图片(' + (index + 1) + ')' + returnjson.用户名 + '--' + returnjson.文案.substring(0, 10) + '--' + returnjson.小红书ID + returnjson.下载.下载状态;
  1171. 正常 = true;
  1172. console.log(xhr.responseText)
  1173. 创建下载记录列表框(下载情况, true, 异常);
  1174. } else if (xhr.status === 404) {
  1175. 下载情况 = '评论图片(' + (index + 1) + ')--网络状态{' + xhr.status + '},资源未找到\n';
  1176. } else if (xhr.status === 500) {
  1177. 下载情况 = '评论图片(' + (index + 1) + ')--网络状态{' + xhr.status + ',服务器内部错误\n';
  1178. } else {
  1179. 下载情况 = '评论图片(' + (index + 1) + ')--网络状态{' + xhr.status + ',网络错误或其他错误\n';
  1180. }
  1181. if (!正常) {
  1182. 按钮.setAttribute('pinglun_button', 'brown')
  1183. 判断服务器();
  1184. }
  1185. showToast(下载情况, 正常);
  1186. }
  1187. };
  1188. xhr.onerror = function () {
  1189. showToast('发生网络错误');
  1190. };
  1191. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  1192. xhr.send(post);
  1193. }
  1194. function 小红书媒体(authorWrapperElements){
  1195. // 遍历匹配的元素列表
  1196. authorWrapperElements.forEach(function(element) {
  1197. if(!element.querySelector('.meiti_button')){
  1198. var xiazai = document.createElement('div');
  1199. xiazai.className = "meiti_button";
  1200. // 添加鼠标点击事件
  1201. xiazai.addEventListener("click", function () {
  1202. xiazai.setAttribute('meiti_button', 'red');
  1203. meiti_send_button
  1204. var linkElement = element.parentNode?.parentNode?.querySelector('a');
  1205. if (linkElement) {
  1206. var link = linkElement.getAttribute('href');
  1207. var 小红书ID = link.substring(link.lastIndexOf('/') + 1);
  1208. if (小红书ID != "") {
  1209. 访问获取笔记源码(小红书ID,0,xiazai);
  1210. }
  1211. }
  1212. })
  1213. element.appendChild(xiazai);
  1214. var meiti_send_button = document.createElement('div');
  1215. meiti_send_button.className = "meiti_send_button";
  1216. // 添加鼠标点击事件
  1217. meiti_send_button.addEventListener("click", function () {
  1218. meiti_send_button.setAttribute('meiti_send_button', 'red');
  1219. var linkElement = element.parentNode?.parentNode?.querySelector('a');
  1220. if (linkElement) {
  1221. var link = linkElement.getAttribute('href');
  1222. var 小红书ID = link.substring(link.lastIndexOf('/') + 1);
  1223. if (小红书ID != "") {
  1224. 访问获取笔记源码(小红书ID,1,meiti_send_button);
  1225. }
  1226. }
  1227. })
  1228. element.appendChild(meiti_send_button);
  1229. }
  1230. });
  1231. }
  1232. function 评论媒体(authorWrapperElements) {
  1233. // 遍历匹配的元素列表
  1234. authorWrapperElements.forEach(function (element) {
  1235. if (!element.querySelector('.pinglun_button')) {
  1236. var xiazai = document.createElement('div');
  1237. xiazai.className = "pinglun_button";
  1238. // 添加鼠标点击事件
  1239. xiazai.addEventListener("click", function () {
  1240. xiazai.setAttribute('pinglun_button', 'red');
  1241. var linkElement = element.parentNode?.parentNode?.parentElement?.id;
  1242. if (linkElement) {
  1243. var 小红书ID = linkElement.substring(linkElement.lastIndexOf('-') + 1)
  1244. if (小红书ID != "") {
  1245. outerLoop: for (var i = 0; i < globalJSON.length; i++) {
  1246. const comments = globalJSON[i]?.data?.comments;
  1247. if (comments) {
  1248. for (var j = 0; j < comments.length; j++) {
  1249. if (comments[j].id === 小红书ID) {
  1250. let url, 文件名, 文件名ID, 用户名, 用户id, 文件类型, 文案, json;
  1251. url = comments[j].pictures[0].url_default;
  1252. if (url) {
  1253. 文件名ID = url.match(/([^/]+)$/)[0].split('!')[0]
  1254. 文案 = comments[j].content;
  1255. 用户名 = comments[j].user_info?.nickname;
  1256. 用户id = comments[j].user_info.user_id;
  1257. 文件名 = 用户名 + '----' + comments[j].note_id + '----{评论}' + 文案 + '----' + 用户id + '----' + 文件名ID + '----' + 时间转换(comments[j].create_time) + '(1).png'
  1258. 文件名 = 文件名.replace(/[\\/:*?"<>|,;#%]/g, '');
  1259. 文件类型 = 'png';
  1260. json = JSON数据(url, 文件名ID, 文案, 用户名, 用户id, 文件保存目录, 文件名, 文件类型, 小红书ID)
  1261. 评论图片下载(json, 0, xiazai);
  1262. break outerLoop; // 退出外部循环
  1263. }
  1264. }
  1265. const sub_comments = comments[j].sub_comments
  1266. for (var k = 0; k < sub_comments.length; k++) {
  1267. let url, 文件名, 文件名ID, 用户名, 用户id, 文件类型, 文案, json;
  1268. if (sub_comments[k].id === 小红书ID) {
  1269. url = sub_comments[k].pictures[0].url_default
  1270. if (url) {
  1271. url = sub_comments[k].pictures[0].url_default;
  1272. 文件名ID = url.match(/([^/]+)$/)[0].split('!')[0]
  1273. 文案 = sub_comments[k].content;
  1274. 用户名 = sub_comments[k].user_info?.nickname;
  1275. 用户id = sub_comments[k].user_info.user_id;
  1276. 文件名 = 用户名 + '----' + sub_comments[k].note_id + '----{评论}' + 文案 + '----' + 用户id + '----' + 文件名ID + '----' + 时间转换(sub_comments[k].create_time + '(1).png')
  1277. 文件名 = 文件名.replace(/[\\/:*?"<>|,;#%]/g, '');
  1278. 文件类型 = 'png';
  1279. json = JSON数据(url, 文件名ID, 文案, 用户名, 用户id, 文件保存目录, 文件名, 文件类型, 小红书ID)
  1280. 评论图片下载(json, 0, xiazai);
  1281. break outerLoop; // 退出外部循环
  1282. }
  1283. }
  1284. }
  1285. }
  1286. }
  1287. }
  1288. }
  1289. }
  1290. })
  1291. element.appendChild(xiazai);
  1292. }
  1293. // 在这里执行你的逻辑操作
  1294. });
  1295. }
  1296. function 评论框(authorWrapperElements) {
  1297. // 遍历匹配的元素列表
  1298. authorWrapperElements.forEach(function (element) {
  1299. element.querySelector('.chat-wrapper')?.remove();
  1300. //创建本地解析笔记按钮
  1301. if (!element.querySelector('.meiti_button')) {
  1302. var xiazai = document.createElement('div');
  1303. xiazai.className = "meiti_button";
  1304. xiazai.style.margin = '5px';
  1305. xiazai.style.display = 'inline-block';
  1306. xiazai.style.verticalAlign = 'middle';
  1307. // 添加鼠标点击事件
  1308. xiazai.addEventListener("click", function () {
  1309. // xiazai.setAttribute('meiti_button', 'red');
  1310. // let 小红书ID,url,文案,文件名ID,文件名,文件保存目录,文件类型,时间,页面url;
  1311. // 页面url=window.location.href;
  1312. // 小红书ID=页面url.match(/\b[A-Fa-f0-9]{16,}\b/g);
  1313. // 文案 = (document.querySelector('#detail-title').textContent + document.querySelector('#detail-desc').textContent).substring(0, 110)
  1314. if (document.querySelector('.close.close-mask-white')) {
  1315. let 小红书ID = window.location.href.match(/\b[A-Fa-f0-9]{16,}\b/g);
  1316. 访问获取笔记源码(小红书ID, 0, xiazai)
  1317. }
  1318. })
  1319. element.querySelector('.share-wrapper').appendChild(xiazai);
  1320. //创建发送笔记URL至网页文件下载按钮
  1321. var meiti_send_button = document.createElement('div');
  1322. meiti_send_button.className = "meiti_send_button";
  1323. meiti_send_button.style.margin = '5px';
  1324. meiti_send_button.style.display = 'inline-block';
  1325. meiti_send_button.style.verticalAlign = 'middle';
  1326. // 添加鼠标点击事件
  1327. meiti_send_button.addEventListener("click", function () {
  1328. let initialStateText = JSON.stringify(unsafeWindow.__INITIAL_STATE__);
  1329. 笔记源码分析(initialStateText, 1, meiti_send_button);
  1330. })
  1331. element.querySelector('.share-wrapper').appendChild(meiti_send_button);
  1332. }
  1333. });
  1334. }
  1335.  
  1336. function JSON数据(url, 文件名ID, 文案, 用户名, 用户id, 目录, 文件名, 文件类型, 小红书ID, prvurl, dfturl) {
  1337. let json = {
  1338. url: url,
  1339. 文件名ID: 文件名ID,
  1340. 文案: 文案,
  1341. 用户名: 用户名,
  1342. 用户id: 用户id,
  1343. 目录: 目录,
  1344. 文件名: 文件名,
  1345. 文件类型: 文件类型,
  1346. 小红书ID: 小红书ID,
  1347. prvurl: prvurl,
  1348. dfturl: dfturl
  1349. };
  1350. return JSON.stringify(json);
  1351. }
  1352. // function 发送数据置下载服务端(post){
  1353. // var xhr = new XMLHttpRequest();
  1354. // xhr.open('POST', 服务器地址, false); // 第三个参数设置为false表示同步请求
  1355. // xhr.send(post);
  1356. // if (xhr.status === 200) {
  1357. // console.log(xhr.responseText);
  1358. // } else {
  1359. // console.log('请求失败:' + xhr.status);
  1360. // }
  1361. // }
  1362.  
  1363.  
  1364. function 时间转换(timestamp) {
  1365. timestamp.toString().padEnd(13, '0');
  1366. // 创建一个新的 Date 对象并使用时间戳初始化它
  1367. var date = new Date(timestamp);
  1368. // 使用 Date 对象的方法获取年、月、日、时、分和秒
  1369. var year = date.getFullYear();
  1370. var month = ('0' + (date.getMonth() + 1)).slice(-2);
  1371. var day = ('0' + date.getDate()).slice(-2);
  1372. var hours = ('0' + date.getHours()).slice(-2);
  1373. var minutes = ('0' + date.getMinutes()).slice(-2);
  1374. var seconds = ('0' + date.getSeconds()).slice(-2);
  1375. // 组合成所需的日期时间格式
  1376. return year + '-' + month + '-' + day + ' ' + hours + ' ' + minutes + ' ' + seconds;
  1377. }
  1378. //复制内容到剪辑版
  1379. function copyToClipboard(text) {
  1380. var textarea = document.createElement('textarea');
  1381. textarea.value = text;
  1382. document.body.appendChild(textarea);
  1383. textarea.select();
  1384. document.execCommand('copy');
  1385. document.body.removeChild(textarea);
  1386. }
  1387. function 请求服务端下载(jsonData, 按钮) {
  1388. get(服务器地址, jsonData, function (response) {
  1389. console.log(response)
  1390. let retrunjson=JSON.parse(response)
  1391. if(retrunjson.下载.网络访问){
  1392. showToast("评论图片:"+retrunjson.用户名+'--'+retrunjson.小红书ID+'--'+retrunjson.下载.网络访问)
  1393. 按钮.setAttribute('pinglun_button','brown')
  1394. }else{
  1395. showToast("评论图片:"+retrunjson.用户名+'--'+retrunjson.小红书ID+'--'+retrunjson.下载.下载状态)
  1396. 按钮.setAttribute('pinglun_button','green')
  1397. }
  1398.  
  1399. });
  1400. }
  1401.  
  1402.  
  1403. function showToast(message, isError) {
  1404. // 创建新的提示框
  1405. const toastContainer = document.createElement('div');
  1406. // 设置样式属性
  1407. toastContainer.style.position = 'fixed';
  1408. toastContainer.style.justifyContent = 'center';
  1409. toastContainer.style.top = '30%';
  1410. toastContainer.style.left = '50%';
  1411. toastContainer.style.width = '65vw';
  1412. toastContainer.style.transform = 'translate(-50%, -50%)';
  1413. toastContainer.style.display = 'flex';
  1414. toastContainer.style.padding = '5px';
  1415. toastContainer.style.fontSize = '20px';
  1416. toastContainer.style.background = '#e7f4ff';
  1417. toastContainer.style.zIndex = '999';
  1418. toastContainer.style.borderRadius = '15px';
  1419. toastContainer.classList.add('PopupMessage'); // 设置 class 名称为 PopupMessage
  1420. // 根据是否为错误提示框添加不同的样式
  1421. if (isError) {
  1422. toastContainer.classList.add('success');
  1423. toastContainer.style.color = '#3fc91d';
  1424. } else {
  1425. toastContainer.classList.add('error');
  1426. toastContainer.style.color = '#CC5500';
  1427. }
  1428. // 将提示框添加到页面中
  1429. document.body.appendChild(toastContainer);
  1430. // 获取页面高度的 20vh
  1431. const windowHeight = window.innerHeight;
  1432. //设置最低的高度。
  1433. const height = windowHeight * 0.2;
  1434. // 设置当前提示框的位置
  1435. toastContainer.style.top = `${height}px`;
  1436. // 在页面中插入新的信息
  1437. const toast = document.createElement('div');
  1438. // 使用 <br> 实现换行
  1439. toast.innerHTML = message.replace(/\n/g, '<br>');
  1440. toastContainer.appendChild(toast);
  1441. // 获取所有的弹出信息元素,包括新添加的元素
  1442. const popupMessages = document.querySelectorAll('.PopupMessage');
  1443. // 调整所有提示框的位置
  1444. let offset = 0;
  1445. popupMessages.forEach(popup => {
  1446. if (popup !== toastContainer) {
  1447. popup.style.top = `${parseInt(popup.style.top) - toast.offsetHeight - 5}px`;
  1448. }
  1449. offset += popup.offsetHeight;
  1450. });
  1451. // 在 3 秒后隐藏提示框
  1452. setTimeout(() => {
  1453. toastContainer.classList.add('hide');
  1454. // 过渡动画结束后移除提示框
  1455. setTimeout(() => {
  1456. toastContainer.parentNode.removeChild(toastContainer);
  1457. }, 300);
  1458. }, 3000);
  1459. }
  1460.  
  1461. //网络请求监测
  1462. (function () {
  1463. // 重写 XMLHttpRequest 对象的 open 方法
  1464. var realOpen = XMLHttpRequest.prototype.open;
  1465. XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
  1466. realOpen.apply(this, arguments);
  1467. };
  1468.  
  1469. // 重写 XMLHttpRequest 对象的 send 方法
  1470. var realSend = XMLHttpRequest.prototype.send;
  1471. XMLHttpRequest.prototype.send = function (data) {
  1472. var self = this;
  1473. var onload = this.onload;
  1474. this.onload = function () {
  1475. var url = self.responseURL;
  1476. // 判断 URL 是否包含 "comment/page" 和 "cursor="
  1477. if (url.includes("comment/page") && url.includes("cursor=")) {
  1478. if (url.includes("cursor=&")) {
  1479. globalJSON = [];
  1480. }
  1481. try {
  1482. // 将响应内容解析为 JSON
  1483. const jsonResponse = JSON.parse(self.responseText);
  1484. // 将 JSON 添加到全局变量
  1485. globalJSON.push(jsonResponse);
  1486. } catch (error) {
  1487. console.log("解析响应内容为 JSON 时出错:", error);
  1488. }
  1489. } else {
  1490. if (url.includes('comment/sub/page')) {
  1491. try {
  1492. // 将响应内容解析为 JSON
  1493. const jsonResponse = JSON.parse(self.responseText);
  1494. // 将 JSON 添加到全局变量
  1495. subJSON.push(jsonResponse);
  1496. console.log("评论包", subJSON);
  1497. } catch (error) {
  1498. console.log("解析响应内容为 JSON 时出错:", error);
  1499. }
  1500. }else{
  1501. if (url.includes('explore/')) {
  1502. try {
  1503. 页面源码=self.responseText;
  1504. console.log("页面源码", subJSON);
  1505. } catch (error) {
  1506. console.log("解析响应内容为 JSON 时出错:", error);
  1507. }
  1508. }
  1509. }
  1510. }
  1511.  
  1512. if (typeof onload === 'function') {
  1513. onload.apply(self, arguments);
  1514. }
  1515. };
  1516. realSend.apply(this, arguments);
  1517. };
  1518.  
  1519. })()
  1520. //元素移动函数
  1521. function dragMenu(menuObj, e) {
  1522. e = e ? e : window.event;
  1523. if (e.target !== menuObj) {
  1524. return; // 如果点击的不是父元素本身,则不执行拖动操作
  1525. }
  1526. // || e.target.tagName === 'BUTTON' 判断是否为按钮元素
  1527. if (e.target.tagName === 'TEXTAREA' || e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') {
  1528. return;
  1529. }
  1530. let dragData = {
  1531. startX: e.clientX,
  1532. startY: e.clientY,
  1533. menuLeft: menuObj.offsetLeft,
  1534. menuTop: menuObj.offsetTop
  1535. };
  1536. document.onmousemove = function (e) { try { dragMenu(menuObj, e); } catch (err) { } };
  1537. document.onmouseup = function (e) { try { stopDrag(menuObj); } catch (err) { } };
  1538. doane(e);
  1539. function stopDrag(menuObj) {
  1540. document.onmousemove = null;
  1541. document.onmouseup = null;
  1542. }
  1543. function doane(e) {
  1544. if (e.stopPropagation) {
  1545. e.stopPropagation();
  1546. } else {
  1547. e.cancelBubble = true;
  1548. }
  1549. if (e.preventDefault) {
  1550. e.preventDefault();
  1551. } else {
  1552. e.returnValue = false;
  1553. }
  1554. }
  1555. document.onmousemove = function (e) {
  1556. let mouseX = e.clientX;
  1557. let mouseY = e.clientY;
  1558. let menuLeft = dragData.menuLeft + mouseX - dragData.startX;
  1559. let menuTop = dragData.menuTop + mouseY - dragData.startY;
  1560. menuObj.style.left = menuLeft + 'px';
  1561. menuObj.style.top = menuTop + 'px';
  1562. doane(e);
  1563. }
  1564. }
  1565.  
  1566. // 监测页面请求()
  1567. // function 监测页面请求(){
  1568. // // 拦截 XMLHttpRequest 请求
  1569. // var realXhr = window.XMLHttpRequest;
  1570. // window.XMLHttpRequest = function () {
  1571. // var xhr = new realXhr();
  1572. // var currentUrl; // 声明 currentUrl 变量
  1573. // // 重写 xhr.open 方法
  1574. // console.log('请求链接',currentUrl);
  1575. // var realOpen = xhr.open;
  1576. // xhr.open = function (method, url, async, user, password) {
  1577. // currentUrl = url; // 将当前请求的 URL 赋值给 currentUrl
  1578. // realOpen.apply(this, arguments);
  1579. // };
  1580. // // 重写 xhr.send 方法
  1581. // var realSend = xhr.send;
  1582. // xhr.send = function (data) {
  1583. // this.addEventListener('load', function () {
  1584. // // 判断是否包含有 "comment/page" 和 "cursor=" 的 URL 请求
  1585. // console.log('响应链接',currentUrl);
  1586. // if (currentUrl.includes("comment/page") && currentUrl.includes("cursor=")) {
  1587. // if(currentUrl.includes("cursor=&")){
  1588. // globalJSON = [];
  1589. // }
  1590. // // console.log("响应状态码:", xhr.status);
  1591. // // console.log("响应头:", xhr.getAllResponseHeaders());
  1592. // // console.log("响应体:", xhr.responseText);
  1593. // try {
  1594. // // 将响应内容解析为 JSON
  1595. // const jsonResponse = JSON.parse(xhr.responseText);
  1596. // // 将 JSON 添加到全局变量
  1597. // globalJSON.push(jsonResponse);
  1598. // // var secondMember = globalJSON[1]?.data?.comments[0]?.content;
  1599. // console.log("评论包", jsonResponse);
  1600. // } catch (error) {
  1601. // console.log("解析响应内容为 JSON 时出错:", error);
  1602. // }
  1603. // }
  1604. // //更多回复
  1605. // if (currentUrl.includes("comment/sub/page")) {
  1606. // // console.log("响应状态码:", xhr.status);
  1607. // // console.log("响应头:", xhr.getAllResponseHeaders());
  1608. // // console.log("响应体:", xhr.responseText);
  1609. // try {
  1610. // // 将响应内容解析为 JSON
  1611. // const jsonResponse = JSON.parse(xhr.responseText);
  1612. // // 将 JSON 添加到全局变量
  1613. // subJSON.push(jsonResponse);
  1614. // // var secondMember = globalJSON[1]?.data?.comments[0]?.content;
  1615. // console.log("评论包",jsonResponse);
  1616. // } catch (error) {
  1617. // console.log("解析响应内容为 JSON 时出错:", error);
  1618. // }
  1619. // }
  1620. // });
  1621. // realSend.apply(this, arguments);
  1622. // };
  1623. // // 重写 xhr.setRequestHeader 方法
  1624. // var realSetRequestHeader = xhr.setRequestHeader;
  1625. // xhr.setRequestHeader = function (header, value) {
  1626. // realSetRequestHeader.apply(this, arguments);
  1627. // };
  1628. // // 重写 xhr.getRequestHeader 方法
  1629. // var realGetRequestHeader = xhr.getRequestHeader;
  1630. // xhr.getRequestHeader = function (header) {
  1631. // return realGetRequestHeader.apply(this, arguments);
  1632. // };
  1633. // return xhr;
  1634. // };
  1635. // }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址