simpleocr / youhou.js
sonygod's picture
油猴脚本
14e8f07
// ==UserScript==
// @name HeiMuer TV Video Player
// @namespace http://tampermonkey.net/
// @version 0.3
// @description Add video player for HeiMuer TV
// @author You
// @match https://heimuer.tv/index.php/vod/detail/id/*
// @grant GM_log
// @require https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.4.10/hls.min.js
// ==/UserScript==
(function () {
'use strict';
const processedUrls = new Set();
let currentHls = null;
function createVideoPlayer() {
// Create main panel
const panelDiv = document.createElement('div');
panelDiv.className = 'stui-pannel clearfix';
// Create header
const headDiv = document.createElement('div');
headDiv.className = 'stui-pannel__head clearfix';
// Create title
const title = document.createElement('h3');
title.className = 'title';
title.textContent = '在线播放';
headDiv.appendChild(title);
// Create episode list container
const episodeListDiv = document.createElement('div');
episodeListDiv.className = 'episode-list';
episodeListDiv.style.cssText = 'margin: 10px 0; display: flex; flex-wrap: wrap; gap: 5px;';
headDiv.appendChild(episodeListDiv);
// Create video wrapper
const wrapper = document.createElement('div');
wrapper.className = 'video-wrapper';
wrapper.style.cssText = 'width: 100%; position: relative; aspect-ratio: 16/9;';
// Create video container
const container = document.createElement('div');
container.className = 'custom-video-player';
container.style.cssText = 'position: absolute; top: 0; left: 0; width: 100%; height: 100%;';
// Create video element
const video = document.createElement('video');
video.controls = true;
video.style.cssText = 'width: 100%; height: 100%; object-fit: contain;';
// Assemble DOM
container.appendChild(video);
wrapper.appendChild(container);
panelDiv.appendChild(headDiv);
panelDiv.appendChild(wrapper);
// Add loading indicator
const loadingDiv = document.createElement('div');
loadingDiv.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.7);
color: white;
padding: 10px 20px;
border-radius: 4px;
display: none;
`;
loadingDiv.textContent = '加载中...';
container.appendChild(loadingDiv);
return {
container: panelDiv,
episodeList: episodeListDiv,
video: video,
playUrl: function (url) {
loadingDiv.style.display = 'block';
if (currentHls) {
currentHls.destroy();
}
const tryPlay = () => {
video.play().catch(error => {
console.log("Retrying autoplay...");
setTimeout(tryPlay, 1000);
});
};
if (Hls.isSupported()) {
currentHls = new Hls();
currentHls.loadSource(url);
currentHls.attachMedia(video);
currentHls.on(Hls.Events.MANIFEST_LOADED, () => {
console.log("Manifest loaded");
});
currentHls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log("Manifest parsed");
loadingDiv.style.display = 'none';
tryPlay();
});
currentHls.on(Hls.Events.ERROR, (event, data) => {
console.log("HLS error:", data);
loadingDiv.style.display = 'none';
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url;
video.addEventListener('loadedmetadata', () => {
loadingDiv.style.display = 'none';
tryPlay();
});
}
}
};
}
function init() {
const descDiv = document.getElementById('desc');
if (!descDiv) return;
// Parse all episodes
const episodes = [];
document.querySelectorAll('.hidden-xs').forEach(el => {
const text = el.textContent || '';
if (text.includes('m3u8.heimuertv.com')) {
const [number, fullUrl] = text.split('$');
const url = fullUrl.match(/https:\/\/m3u8\.heimuertv\.com\/play\/[\w\.]+\.m3u8/)?.[0];
if (url) {
console.log('Episode number:', number); // Debug log
episodes.push({ number, url });
}
}
});
if (episodes.length > 0) {
// Sort episodes
episodes.sort((a, b) => Number(a.number) - Number(b.number));
// Create player
const player = createVideoPlayer();
descDiv.parentNode.insertBefore(player.container, descDiv);
// Create episode buttons
episodes.forEach((episode, idx) => {
const btn = document.createElement('button');
const episodeNum = (idx + 1).toString().padStart(2, '0'); // Convert index to episode number
btn.textContent = `第${episodeNum}集`;
btn.style.cssText = `
padding: 5px 15px;
border: 1px solid ${idx === 0 ? '#007bff' : '#ddd'};
background: ${idx === 0 ? '#007bff' : '#fff'};
color: ${idx === 0 ? '#fff' : '#333'};
border-radius: 3px;
cursor: pointer;
`;
btn.onclick = () => {
// Update button styles
player.episodeList.querySelectorAll('button').forEach(b => {
b.style.background = '#fff';
b.style.color = '#333';
b.style.borderColor = '#ddd';
});
btn.style.background = '#007bff';
btn.style.color = '#fff';
btn.style.borderColor = '#007bff';
// Play episode
player.playUrl(episode.url);
};
player.episodeList.appendChild(btn);
});
// Play first episode
// Trigger initial play with slight delay
setTimeout(() => {
player.playUrl(episodes[0].url);
}, 500);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();