返回列表 发布新帖

[网站] 订阅源模板(内容规则)

 
1236 79
发表于 2024-12-18 18:10:30 来自手机 | 查看全部 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 良有益 于 2024-12-19 16:02 编辑

多功能订阅源模板升级了,次此次加了css,调试信息,错误多次加载!测试了秀人、小h书、福利兔,其他请自测
介绍:
1.提取视频地址
2.视频播放
3.视频换源
4.提取图片
5.提取文本
基本上只需要在配置项里填写即可,如果页码不对就需要改循环,基本上都是是问题不大,有些异步加载的不行,不会弄,大佬可以改。
像福利兔,可以互换src与data-original属性值;就改配置项里的互换值即可,以下是效果图。
鉴于有小白不会,就加一个秀人模板不知道怎么上传文件,只能放链接)
7天有效时间:
https://shuyuan.mgz6.com/shuyuan/b2f838e8d12910855f53f766389bf9da.json
1000278115.webp
1000278116.webp
1000278117.webp

评分

参与人数 1源币 +8 贡献 +2 收起 理由
Thomas喲 + 8 + 2

查看全部评分

评论79

良有益楼主Lv.3 发表于 2024-12-18 18:11:20 来自手机 | 查看全部
<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <title>多功能内容展示6.0</title>
  <!-- 引入必要的外部资源 -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js"></script>
  <!-- 当图片加载出来不显示,可以试试下面 {{@@script@html}}-->
  <!-- {{@@script@html}}-->
  <style>
    #title, #loading, #page { margin: 0 auto; font-size: 20px; text-align: center; }
    #description, #urls, #video-url, #video-sources, #messages, #text, #try-loading { width: 90%; max-width: 800px; margin: 10px auto; text-align: left; word-wrap: break-word; white-space: pre-wrap;}
    #images img { width: 100%; height: auto; margin: 3px 0; cursor: pointer; }
    #video-container video { width: 100%; margin: 10px auto; display: block; }
    #video-source-select { width: calc(100% - 22px); margin-top: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; margin-bottom: 20px; box-sizing: border-box; display: none; }
    #messages, #video-container, #urls, #try-loading { display: none; }
    br { display: block; }
    #toggle-buttons-container { width: fit-content; margin: 10px auto; display: flex; justify-content: center; flex-wrap: wrap; }
    #toggle-urls-btn, #toggle-messages-btn { margin: 0 10px; }
    .error-message,.final-error-message { color: red; }
  </style>
</head>

<body>
  <!-- 页面标题、简介、页码 -->
  <h3 id="title">{{@@.title@text||h1@text||h2@text||title@text}}</h3>
  <p id="description">{{@@.info@html||.jianjie@html}}</p >
  <p id="page">共<span id="total-pages">1</span>页</p >
  <!-- 加载进度信息 -->
  <div id="loading">正在加载:第1页</div>
  <!-- 显示/隐藏按钮容器 -->
  <div id="toggle-buttons-container">
    <button id="toggle-urls-btn">显示/隐藏拼接网址</button>
    <button id="toggle-messages-btn">显示/隐藏调试信息</button>
  </div>
  <!-- 显示拼接的URL列表 -->
  <div id="urls"></div>
  <!-- 调试信息显示 -->
  <div id="messages"></div>
  <!-- 视频地址、视频容器、视频源选择 -->
  <div id="video-url"></div>
  <select id="video-source-select" onchange="updateVideoSource()"></select>
  <div id="video-container">
    <video id="video-element" controls></video>
  </div>
  <!-- 图片容器、文本容器 -->
  <div id="images"></div>
  <div id="text"></div>
  <script>
    // 配置项
    const config = {
      totalPagesText: '{{@@.page.0@a.-2@textNodes##\n.*}}', // 提取页码数
      videoContainerSelector: 'body', // 视频选择器
      imgContainerSelector: 'div p img', // 图片选择器
      textContainerSelector: '.content p', // 文本选择器
      pageUrlText: '{urlPrefix}_{i}.html', // 地址拼接,urlPrefix+_+i+.html
      shouldSwapSrcAndDataOriginal: false, // 图片src与data-original互换,true互换
      showMessagesOnce: true, // 输出一次
      delayTime: 3000, // 页码加载延迟时间retry
      retrydelayTime: 5000, // 错误加载延迟时间
      maxLoadAttempts: 3 // 最大加载尝试次数
    };

    let videoSources = [];
    let loadAttempts = {};
    let urls = [];
    let hls;
    let imageBox;

    // 获取页面总数
    const totalPagesText = config.totalPagesText;
    const totalPages = parseInt(totalPagesText) || 1;
    $('#total-pages').text(totalPages);

    // 获取基础URL
    const baseUrl = '{{baseUrl}}'; // 示例基础URL

    // 构建URL前缀
    const urlPrefix = baseUrl.replace(/\.html$/, '');

    // 根据页面数量构建URL数组
    if (totalPages === 1) {
      urls.push(baseUrl);
    } else {
      urls.push(baseUrl);
      for (let i = 2; i <= totalPages; i++) {
        urls.push(config.pageUrlText.replace('{urlPrefix}', urlPrefix).replace('{i}', i));
      }
    }

    // 显示拼接的URL列表
    $('#urls').html('<p>拼接的网址:</p >').append(urls.map((url, index) => `<p>${index + 1}: ${url}</p >`).join(''));

    // 辅助函数:交换src和data-original属性
    function swapSrcAndDataOriginal(element, shouldSwap) {
      if (shouldSwap) {
        const src = element.attr('src');
        const dataOriginal = element.attr('data-original');
        if (src && dataOriginal) {
          element.attr('src', dataOriginal);
          element.attr('data-original', src);
        }
      }
      return element.attr('src');
    }

    // 内容加载函数,提取图片、视频、文本
    function loadContent(urls, index = 0, hasVideo = false) {
      if (index >= urls.length) {
        $('#loading').hide();
        $('#try-loading').hide(); // 完成加载后隐藏
        return;
      }

      // 更新加载进度
      const progress = Math.round((index / urls.length) * 100);
      $('#loading').text(`正在加载第${index + 1}页`);
      // 输出当前页地址到messages元素
      $('#messages').append(`<p>当前地址: ${urls[index]}</p >`);

      // 发送AJAX请求获取页面内容
      $.ajax({
        url: urls[index],
        type: 'GET',
        success: function (data) {
          try {
            const $data = $(data);
            let updatedHtmlContent = data.replace(/(?<!https?(?<![-a-zA-Z0-9+&@#/%?=~_|!:,.;]*)(\/\/)(?!\/)/g, `${window.location.protocol}//`);

            // 创建一个新的DOMParser实例来安全地解析HTML内容
            const parser = new DOMParser();
            const doc = parser.parseFromString(updatedHtmlContent, "text/html");

            // 提取视频地址
            // 方法1:提取video标签的属性地址
            const videoContents = $(doc).find(config.videoContainerSelector);
            const videoTags = $(videoContents).find('video');
            videoTags.each(function () {
              const videosrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original');
              if (videosrc) {
                videoSources.push(videosrc);
              }

              // 提取source标签的src属性
              const sources = $(this).find('source');
              sources.each(function () {
                const sourceSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original');
                if (sourceSrc) {
                  videoSources.push(sourceSrc);
                }
              });
            });

            // 方法2:使用正则表达式匹配视频地址
            const regex = /https?:\/\/[\w.-]+(?:\/[^\s]*)?(?:\.(m3u8|mp4|webm|ogg|flv))(?:\.[^\s"']*)*/ig;
            const matches = data.match(regex);
            if (matches) {
              const uniqueMatches = matches.filter((value, idx, self) => self.indexOf(value) === idx);
              videoSources = videoSources.concat(uniqueMatches);
            }

            // 方法3:正则表达式匹配非正常视频
            const domainMatch = updatedHtmlContent.match(/var domain = "([^"]+)";/);
            const scriptContentMatches = [...updatedHtmlContent.matchAll(/var videos = ([^;]+);/g)];
            if (domainMatch && scriptContentMatches.length > 0) {
              const domain = domainMatch[1].replace(/\/+$/, '');
              const tempVideoUrlsFromScripts = [];
              for (const match of scriptContentMatches) {
                try {
                  const parsedVideos = JSON.parse(match[1].replace(/\\(?=[\\/])|\\[^u]/g, ''));
                  const videoUrls = parsedVideos.map(video => {
                    const urlPath = video.url.replace(/^\/+|\/+$/g, '');
                    const fullUrl = `${domain}/${urlPath}`;
                    return fullUrl;
                  });
                  tempVideoUrlsFromScripts.push(...videoUrls);
                } catch (jsonError) {
                  console.error(`无法解析部分 videos JSON 数据 (${urls[index]}):`, jsonError);
                  $('#messages').append(`<p class="error-message">无法解析部分 videos JSON 数据: ${jsonError.message}</p >`);
                }
              }
              const uniqueVideoUrlsFromScripts = [...new Set(tempVideoUrlsFromScripts)];
              videoSources = [...new Set([...videoSources, ...uniqueVideoUrlsFromScripts])];
            }

            // 对视频源去重
            videoSources = [...new Set(videoSources)];

            // 视频源提取反馈
            if (videoSources.length > 0) {
              $('#messages').append(`<p>成功提取到视频,找到 ${videoSources.length} 个视频。</p >`);
              videoSources.forEach(src => {
                $('#messages').append(`<div>视频地址:<p style="color:red;"> ${src}</p ></div>`);
              });
              populateVideoSelect(videoSources);
            } else {
              $('#messages').append(`<p>未找到视频源。</p >`);
            }

            // 提取图片
            const $imgContents = $(doc).find(config.imgContainerSelector);
            const shouldSwap = config.shouldSwapSrcAndDataOriginal;
            $imgContents.each(function () {
              const $newImg = $(this).clone();
              const imgSrc = swapSrcAndDataOriginal($newImg, shouldSwap);
              if (!/^http/.test(imgSrc)) {
                const baseUrl = urls[index].split('/').slice(0, 3).join('/');
                $newImg.attr('src', baseUrl + imgSrc);
              }
              $('#images').append($newImg);
            });

            // 图片提取反馈
            if ($imgContents.length > 0) {
              $('#messages').append(`<p>成功提取图片,共 ${$imgContents.length} 张。</p >`);
              $imgContents.each(function () {
                const imgSrc = $(this).attr('src') || $(this).attr('data-src') || $(this).attr('data-original');
                $('#messages').append(`<div>地址:<p style="color:red;"> ${imgSrc}</p ></div>`);
              });
            } else {
              $('#messages').append(`<p>未提取到图片。</p >`);
            }

            // 初始化Viewer.js插件,如果#images存在的话
            if ($('#images')[0]) {
              imageBox.viewer.update();
            }

            // 提取文本,保留<br>标签作为换行符
            const textContents = $(doc).find(config.textContainerSelector).map(function () {
              const $currentContents = $(this);
              $currentContents.html($currentContents.html().replace(/<br\s*\/?>/gi, '\n'));
              // 移除当前<p>元素内的所有<img>标签
              $currentContents.find('img').remove();
              return $currentContents.text().trim(); // 纯文本
            }).get().join('\n');

            // 文本提取反馈
            if (textContents.trim()) {
              $('#text').append(`<p>${textContents}</p ><br>`);
              $('#messages').append(`<p>成功提取文本。</p >`);
            } else {
              $('#messages').append(`<p>未提取到文本内容。</p >`);
            }

            // 继续加载下一页
            setTimeout(() => {
              loadContent(urls, index + 1, hasVideo);
            }, config.delayTime);
          } catch (parseError) {
            console.error(`解析页面内容时发生错误 (${urls[index]}):`, parseError);
            $('#messages').append(`<p class="error-message">解析页面内容时发生错误: ${parseError.message}</p >`);
            handleLoadFailure(urls, index, hasVideo);
          }
        },
        error: function () {
          handleLoadFailure(urls, index, hasVideo);
        }
      });
    }

    function handleLoadFailure(urls, index, hasVideo) {
      console.log('内容加载失败:', urls[index]);
      const errorMessage = `内容加载失败: ${urls[index]}`;
      $('#messages').append(`<p class="error-message">${errorMessage}</p >`);

      // 记录加载尝试次数
      if (!loadAttempts[urls[index]]) {
        loadAttempts[urls[index]] = 1;
      } else {
        loadAttempts[urls[index]]++;
      }

      // 如果尝试次数小于等于最大尝试次数,则重新加载
      if (loadAttempts[urls[index]] <= config.maxLoadAttempts) {
        const retryMessage = `第${index + 1}页加载失败,正在进行第${loadAttempts[urls[index]]}次加载!`;
        $('#messages').append(`<p class="retry-message">${retryMessage}</p >`);
        setTimeout(() => {
          loadContent(urls, index, hasVideo);
        }, config.retrydelayTime);
      } else {
        const finalErrorMessage = `第${index + 1}页加载失败,已达到最大尝试次数(${config.maxLoadAttempts})!`;
        $('#messages').append(`<p class="final-error-message">${finalErrorMessage}</p >`);
        $('#loading').hide();

        // 继续加载下一页
        setTimeout(() => {
          loadContent(urls, index + 1, hasVideo);
        }, config.delayTime);
      }
    }

    function populateVideoSelect(sources) {
      const selectElement = document.getElementById('video-source-select');
      sources.forEach((source, index) => {
        const option = document.createElement('option');
        option.value = source;
        option.textContent = `视频源 ${index + 1}`;
        selectElement.appendChild(option);
      });
      selectElement.style.display = 'block';
      updateVideoSource();
    }

    function updateVideoSource() {
      const selectedSource = document.getElementById('video-source-select').value;
      document.getElementById('video-url').textContent = `视频地址: ${selectedSource}`;
      const videoElement = document.getElementById('video-element');
      videoElement.src = selectedSource;
      videoElement.load();

      // 如果是m3u8格式,使用HLS.js
      if (!videoElement.canPlayType('application/vnd.apple.mpegurl') && Hls.isSupported()) {
        if (hls) {
          hls.destroy();
        }
        hls = new Hls();
        hls.loadSource(selectedSource);
        hls.attachMedia(videoElement);
      }

      // 添加调试信息
      $('#messages').append(`<p>更新视频源为: ${selectedSource}</p >`);

      // 显示视频容器
      $('#video-container').show();
    }

    // 辅助函数:根据视频格式返回正确的MIME类型
    function getVideoType(src) {
      const extension = src.split('.').pop().toLowerCase();
      switch (extension) {
        case 'm3u8':
          return 'application/x-mpegURL';
        case 'mp4':
          return 'video/mp4';
        case 'webm':
          return 'video/webm';
        case 'ogg':
          return 'video/ogg';
        case 'flv':
          return 'video/x-flv';
        default:
          return 'video/*';
      }
    }

    // 页面加载完成后执行的函数
    $(document).ready(function () {
      // 初始化图片查看器
      imageBox = document.getElementById('images');
      new Viewer(imageBox, {
        title: true,
        interval: 3000
      });

      // 开始加载内容,初始索引为0,标记是否有视频为false
      loadContent(urls, 0, false);

      // 显隐按钮功能 - 调试信息
      $('#toggle-messages-btn').click(function () {
        $('#messages').toggle();
      });

      // 显隐按钮功能 - 拼接网址
      $('#toggle-urls-btn').click(function () {
        $('#urls').toggle();
      });
    });
  </script>
</body>

</html>
怎么用啊?  详情 回复
发表于 2024-12-27 17:09
回复

使用道具 举报

bing08Lv.4 发表于 2024-12-18 18:16:02 来自手机 | 查看全部
感谢分享
回复

使用道具 举报

qinLv.16 发表于 2024-12-18 18:16:11 来自手机 | 查看全部
感谢分享
回复

使用道具 举报

kissxhhLv.4 发表于 2024-12-18 18:17:14 来自手机 | 查看全部
不明觉厉
回复

使用道具 举报

爱吃猫的鱼 发表于 2024-12-18 18:24:01 来自手机 | 查看全部
感谢分享
回复

使用道具 举报

Sylt1122Lv.5 发表于 2024-12-18 18:39:11 来自手机 | 查看全部
不明觉厉 感谢分享
回复

使用道具 举报

荡神Lv.13 发表于 2024-12-18 18:46:46 来自手机 | 查看全部
感谢分享
回复

使用道具 举报

wsndzrLv.1 发表于 2024-12-18 18:49:30 来自手机 | 查看全部
真的是厉害
回复

使用道具 举报

110Lv.5 发表于 2024-12-18 18:55:20 来自手机 | 查看全部
感谢分享
回复

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

投诉/建议联系

ysqbbs@outlook.com

未经授权禁止转载,复制和建立镜像,
如有违反,追究法律责任
  • 关注公众号
  • 添加QQ群
Copyright © 2001-2025 源社区 版权所有 All Rights Reserved.
关灯 在本版发帖
扫一扫添加QQ群
返回顶部
快速回复 返回顶部 返回列表