File size: 6,983 Bytes
14e8f07 |
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
// ==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();
}
})(); |