<!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> |