[JavaScript] 纯文本查看 复制代码
// ==UserScript==
// @name 南京广播电视台
// @namespace http://tampermonkey.net/
// @version 2.3
// @description 南京广电:看电视/听广播,双击视频全屏,右侧滑动频道列表
// @author 基于南京广播电视台页面调试
// @match https://www.nbs.cn/live/*
// @match http://www.nbs.cn/live/*
// @match http://www.njgb.com/live*
// @match https://www.njgb.com/live*
// @grant GM_addStyle
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// 南京广播电视台频道数据
const NJ_CHANNELS = [
// 电视频道
{ n: '📺 新闻综合频道', u: '/live/?id=109152', icon: '📰', type: 'tv', id: '109152' },
{ n: '📺 教育科技频道', u: '/live/?id=109153', icon: '🎓', type: 'tv', id: '109153' },
{ n: '📺 十八·生活频道', u: '/live/?id=110094', icon: '🏠', type: 'tv', id: '110094' },
{ n: '📺 文旅纪录频道', u: '/live/?id=110093', icon: '✈️', type: 'tv', id: '110093' },
{ n: '📺 少儿频道', u: '/live/?id=110095', icon: '🧸', type: 'tv', id: '110095' },
// 广播频率
{ n: '📻 新闻综合广播 FM106.9', u: 'http://www.njgb.com/live/?id=fm1069', icon: '🎙️', type: 'fm', id: 'fm1069' },
{ n: '📻 交通广播 FM102.4', u: 'http://www.njgb.com/live/?id=fm1024', icon: '🚗', type: 'fm', id: 'fm1024' },
{ n: '📻 音乐广播 FM105.8', u: 'http://www.njgb.com/live/?id=fm1058', icon: '🎵', type: 'fm', id: 'fm1058' },
{ n: '📻 体育广播 FM104.3', u: 'http://www.njgb.com/live/?id=fm1043', icon: '⚽', type: 'fm', id: 'fm1043' },
{ n: '📻 城市管理广播 FM96.6', u: 'http://www.njgb.com/live/?id=fm966', icon: '🏙️', type: 'fm', id: 'fm966' },
{ n: '📻 经济广播 FM98.1', u: 'http://www.njgb.com/live/?id=fm981', icon: '💰', type: 'fm', id: 'fm981' }
];
// 先添加基础样式,确保页面布局正确但不干扰DPlayer初始化
GM_addStyle(`
/* 只隐藏广告和导航等干扰元素,保留播放器区域完全不受影响 */
header, .header-main, .menu-box, .wrap1_2014_mod3, .wrap1_hot_main,
.mian_list_1, .mian_list_3, .footer, .d2,
.wrap2_2014_mian .mian_t, .fl, .mt10,
.mian_db, .mian_zb, .channel_list, .main-top,
.main-bottom, .time-list, .program-list,
.head2015, .content-nav, .footer_c, .clear, .mb15,
.zb_c .content-nav ul, .zb_c .content-nav li,
.zb_contit, .zb_con .zb_contit,
.nav_search, .header-right, .niuka-box, .logo-icon, .menu-list,
.menu-item, .wrap1_hot_main ul, .wrap1_hot_main li,
[class*="ad"], [class*="banner"], [class*="copyright"],
iframe:not([src*="m3u8"]):not([src*="hls"]),
.breadcrumb, .recommend, .comment, .share {
display: none !important;
}
/* 保留页面基本结构,确保播放器能正常初始化 */
html, body {
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
height: 100vh !important;
width: 100vw !important;
overflow: hidden !important;
}
/* 播放器容器 - 全屏显示 */
.page-main, .wrap2_2014, .wrap2_2014_mian {
margin: 0 !important;
padding: 0 !important;
width: 100vw !important;
height: 100vh !important;
background: #000 !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
overflow: hidden !important;
}
.videochannel, .video_c {
width: 100vw !important;
height: 100vh !important;
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
}
.video_a {
width: 100% !important;
height: 100% !important;
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
position: relative !important;
}
/* DPlayer容器 - 确保全屏 */
#dplayer {
width: 100% !important;
height: 100% !important;
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
}
/* 保留原生频道切换栏但移到顶部 */
.mian_list_2 {
display: block !important;
position: fixed !important;
top: 20px !important;
left: 50% !important;
transform: translateX(-50%) !important;
z-index: 1000 !important;
background: rgba(0,0,0,0.7) !important;
border-radius: 30px !important;
padding: 5px !important;
backdrop-filter: blur(10px) !important;
border: 1px solid rgba(204,145,29,0.3) !important;
}
.mian_list_2 .tv_list {
background: none !important;
width: auto !important;
height: auto !important;
display: flex !important;
gap: 2px !important;
margin: 0 !important;
padding: 0 !important;
}
.mian_list_2 .tv_list li {
width: auto !important;
height: auto !important;
line-height: normal !important;
margin: 0 !important;
padding: 8px 16px !important;
color: #fff !important;
border-radius: 25px !important;
cursor: pointer !important;
font-size: 14px !important;
transition: all 0.3s !important;
background: transparent !important;
list-style: none !important;
border: 1px solid transparent !important;
}
.mian_list_2 .tv_list li:hover {
background: rgba(204,145,29,0.3) !important;
border-color: rgba(204,145,29,0.5) !important;
}
.mian_list_2 .tv_list li.current {
background: #cc911d !important;
color: #fff !important;
}
/* 广播页面样式 */
.zb_c, .zb_con {
width: 100vw !important;
height: 100vh !important;
margin: 0 !important;
padding: 0 !important;
background: #000 !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
}
.video_cont {
width: 100% !important;
height: 100% !important;
padding: 0 !important;
margin: 0 !important;
background: #000 !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
position: relative !important;
}
/* 广播页面隐藏原生音频控件 */
#Html5Video, .video_cont audio, .video_cont video {
width: 0 !important;
height: 0 !important;
opacity: 0 !important;
pointer-events: none !important;
position: absolute !important;
}
/* 自定义广播播放器 */
.nj-fm-player {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
background: linear-gradient(145deg, #111 0%, #1a1a1a 100%) !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
color: white !important;
font-family: 'Microsoft YaHei', sans-serif !important;
z-index: 2000 !important;
backdrop-filter: blur(5px) !important;
}
.nj-fm-background {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
background: radial-gradient(circle at 30% 30%, #333, #000) !important;
opacity: 0.4 !important;
z-index: -1 !important;
}
.nj-fm-cover {
width: 280px !important;
height: 280px !important;
border-radius: 50% !important;
background: #222 !important;
box-shadow: 0 20px 40px rgba(0,0,0,0.8), 0 0 0 4px rgba(204,145,29,0.3) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
margin-bottom: 40px !important;
transition: transform 0.5s ease !important;
}
.nj-fm-cover.playing {
animation: rotate 20s linear infinite !important;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.nj-fm-cover span {
font-size: 120px !important;
filter: drop-shadow(0 10px 10px rgba(0,0,0,0.5)) !important;
}
.nj-fm-info {
text-align: center !important;
margin-bottom: 30px !important;
}
.nj-fm-title {
font-size: 32px !important;
font-weight: bold !important;
color: #fff !important;
text-shadow: 0 2px 10px rgba(204,145,29,0.5) !important;
margin-bottom: 8px !important;
}
.nj-fm-subtitle {
font-size: 16px !important;
color: #aaa !important;
letter-spacing: 2px !important;
}
.nj-fm-controls {
display: flex !important;
align-items: center !important;
gap: 30px !important;
background: rgba(30,30,30,0.7) !important;
backdrop-filter: blur(10px) !important;
padding: 15px 40px !important;
border-radius: 60px !important;
border: 1px solid rgba(204,145,29,0.2) !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.5) !important;
}
.nj-fm-btn {
width: 50px !important;
height: 50px !important;
border-radius: 50% !important;
background: #333 !important;
border: none !important;
color: #cc911d !important;
font-size: 24px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
}
.nj-fm-btn:hover {
background: #cc911d !important;
color: #fff !important;
transform: scale(1.1) !important;
}
.nj-fm-btn.play-pause {
width: 70px !important;
height: 70px !important;
background: #cc911d !important;
color: #fff !important;
font-size: 32px !important;
}
.nj-fm-btn.play-pause:hover {
background: #e6a72a !important;
}
.nj-fm-volume {
display: flex !important;
align-items: center !important;
gap: 10px !important;
margin-left: 20px !important;
}
.nj-fm-volume-slider {
width: 100px !important;
height: 4px !important;
-webkit-appearance: none !important;
background: #444 !important;
border-radius: 2px !important;
outline: none !important;
}
.nj-fm-volume-slider::-webkit-slider-thumb {
-webkit-appearance: none !important;
width: 16px !important;
height: 16px !important;
border-radius: 50% !important;
background: #cc911d !important;
cursor: pointer !important;
box-shadow: 0 0 8px #cc911d !important;
}
.nj-fm-volume-icon {
color: #cc911d !important;
font-size: 20px !important;
width: 30px !important;
text-align: center !important;
}
/* 右侧滑动菜单 */
.nj-right-menu {
position: fixed !important;
right: -320px !important;
top: 0 !important;
width: 300px !important;
height: 100vh !important;
background: rgba(10, 10, 10, 0.98) !important;
backdrop-filter: blur(20px) !important;
border-left: 1px solid rgba(204, 145, 29, 0.3) !important;
z-index: 1000000 !important;
display: flex !important;
flex-direction: column !important;
box-shadow: -2px 0 20px rgba(0,0,0,0.5) !important;
font-family: "Microsoft YaHei", sans-serif !important;
transition: right 0.3s ease !important;
}
.nj-right-menu.open {
right: 0 !important;
}
.nj-menu-header {
padding: 25px 20px !important;
background: linear-gradient(135deg, #cc911d 0%, #b37b1a 100%) !important;
border-bottom: 1px solid rgba(255,255,255,0.1) !important;
display: block !important;
visibility: visible !important;
opacity: 1 !important;
position: relative !important;
z-index: 1000001 !important;
}
.nj-menu-header h2 {
color: #fff !important;
margin: 0 0 8px 0 !important;
font-size: 22px !important;
font-weight: bold !important;
text-shadow: 0 2px 4px rgba(0,0,0,0.3) !important;
}
.nj-menu-header p {
color: rgba(255,255,255,0.9) !important;
margin: 0 !important;
font-size: 14px !important;
font-weight: normal !important;
}
.nj-menu-tabs {
display: flex !important;
padding: 15px 15px 10px !important;
gap: 10px !important;
border-bottom: 1px solid #333 !important;
}
.nj-tab-btn {
flex: 1 !important;
padding: 8px 12px !important;
background: transparent !important;
border: 1px solid #444 !important;
color: #999 !important;
border-radius: 20px !important;
cursor: pointer !important;
font-size: 14px !important;
font-weight: 500 !important;
transition: all 0.2s ease !important;
}
.nj-tab-btn:hover {
background: rgba(204, 145, 29, 0.2) !important;
border-color: #cc911d !important;
color: #cc911d !important;
}
.nj-tab-btn.active {
background: #cc911d !important;
border-color: #cc911d !important;
color: #fff !important;
}
.nj-channel-list {
flex: 1 !important;
overflow-y: auto !important;
padding: 15px !important;
}
.nj-channel-item {
display: flex !important;
align-items: center !important;
padding: 12px 15px !important;
margin: 6px 0 !important;
color: #ccc !important;
text-decoration: none !important;
border-radius: 12px !important;
transition: all 0.2s ease !important;
border: 1px solid transparent !important;
background: rgba(255,255,255,0.03) !important;
cursor: pointer !important;
}
.nj-channel-item:hover {
background: rgba(204, 145, 29, 0.15) !important;
border-color: rgba(204, 145, 29, 0.3) !important;
transform: translateX(-5px) !important;
}
.nj-channel-item.active {
background: #cc911d !important;
color: #fff !important;
box-shadow: 0 4px 10px rgba(204, 145, 29, 0.3) !important;
}
.nj-channel-icon {
width: 40px !important;
height: 40px !important;
background: rgba(255,255,255,0.1) !important;
border-radius: 10px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
margin-right: 12px !important;
font-size: 22px !important;
}
.nj-channel-item.active .nj-channel-icon {
background: rgba(255,255,255,0.2) !important;
}
.nj-channel-info {
flex: 1 !important;
}
.nj-channel-name {
font-size: 15px !important;
font-weight: 500 !important;
margin-bottom: 4px !important;
}
.nj-channel-type {
font-size: 11px !important;
opacity: 0.7 !important;
}
.nj-menu-footer {
padding: 15px 20px !important;
border-top: 1px solid #333 !important;
color: #888 !important;
font-size: 12px !important;
text-align: center !important;
background: rgba(0,0,0,0.3) !important;
}
.nj-menu-toggle {
position: fixed !important;
right: 20px !important;
top: 50% !important;
transform: translateY(-50%) !important;
width: 48px !important;
height: 48px !important;
background: #cc911d !important;
border-radius: 24px 0 0 24px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
color: #fff !important;
font-size: 24px !important;
cursor: pointer !important;
z-index: 1000001 !important;
box-shadow: -2px 0 15px rgba(0,0,0,0.4) !important;
transition: right 0.3s ease, background 0.2s ease !important;
border: 2px solid rgba(255,255,255,0.2) !important;
border-right: none !important;
padding: 0 !important;
}
.nj-menu-toggle:hover {
background: #e6a72a !important;
transform: translateY(-50%) scale(1.05) !important;
}
.nj-menu-toggle.menu-open {
right: 300px !important;
}
.nj-current-channel-hint {
position: fixed !important;
top: 20px !important;
left: 20px !important;
background: rgba(0,0,0,0.7) !important;
color: #fff !important;
padding: 10px 20px !important;
border-radius: 30px !important;
font-size: 15px !important;
font-weight: 500 !important;
z-index: 999999 !important;
backdrop-filter: blur(10px) !important;
border: 1px solid rgba(204,145,29,0.3) !important;
pointer-events: none !important;
box-shadow: 0 4px 15px rgba(0,0,0,0.3) !important;
}
.nj-fullscreen-hint {
position: fixed !important;
bottom: 20px !important;
right: 80px !important;
color: rgba(255,255,255,0.7) !important;
font-size: 13px !important;
background: rgba(0,0,0,0.5) !important;
padding: 6px 14px !important;
border-radius: 30px !important;
z-index: 999999 !important;
backdrop-filter: blur(5px) !important;
border: 1px solid rgba(255,255,255,0.1) !important;
pointer-events: none !important;
transition: opacity 0.3s ease !important;
letter-spacing: 0.5px !important;
}
.nj-fullscreen-hint.hidden {
opacity: 0 !important;
}
.nj-channel-list::-webkit-scrollbar {
width: 4px !important;
}
.nj-channel-list::-webkit-scrollbar-track {
background: #222 !important;
}
.nj-channel-list::-webkit-scrollbar-thumb {
background: #cc911d !important;
border-radius: 2px !important;
}
`);
// 当前选中的标签
let currentTab = 'tv';
let menuOpen = false;
let fmPlayer = null;
let audioElement = null;
let dplayerInitialized = false;
// 判断页面类型
function getPageType() {
return location.hostname.includes('njgb.com') ? 'fm' : 'tv';
}
// 获取当前频道
function getCurrentChannel() {
const searchParams = new URLSearchParams(location.search);
const id = searchParams.get('id');
if (id) {
const channel = NJ_CHANNELS.find(c => c.id === id);
if (channel) return channel;
}
return NJ_CHANNELS.find(c => location.href.includes(c.u)) || NJ_CHANNELS[0];
}
// 切换频道
function switchChannel(channel) {
if (channel.type === 'tv') {
location.href = channel.u.startsWith('http') ? channel.u : 'https://www.nbs.cn' + channel.u;
} else {
location.href = channel.u;
}
}
// 更新标签按钮状态
function updateTabsState() {
const menu = document.querySelector('.nj-right-menu');
if (!menu) return;
menu.querySelectorAll('.nj-tab-btn').forEach(btn => {
btn.classList.toggle('active', btn.dataset.tab === currentTab);
});
}
// 渲染频道列表
function renderChannelList(filter) {
const menu = document.querySelector('.nj-right-menu');
if (!menu) return;
const list = menu.querySelector('#nj-channel-list');
if (!list) return;
list.innerHTML = '';
NJ_CHANNELS.forEach(item => {
if (item.type !== filter) return;
const div = document.createElement('div');
div.className = 'nj-channel-item';
if (location.href.includes(item.u) || location.search.includes(item.id)) {
div.classList.add('active');
}
div.innerHTML = `
<div class="nj-channel-icon">${item.icon}</div>
<div class="nj-channel-info">
<div class="nj-channel-name">${item.n.replace(/[📺📻]\s/, '')}</div>
<div class="nj-channel-type">${item.type === 'tv' ? '电视频道' : '广播频率'}</div>
</div>
`;
div.addEventListener('click', (e) => {
e.preventDefault();
switchChannel(item);
});
list.appendChild(div);
});
}
// 创建右侧滑动菜单
function createRightMenu() {
if (document.querySelector('.nj-right-menu')) {
console.log('菜单已存在,跳过创建');
return;
}
console.log('创建右侧菜单');
const now = new Date();
const timeStr = now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
currentTab = getPageType();
console.log('当前时间:', timeStr);
console.log('频道数量:', NJ_CHANNELS.length);
const menu = document.createElement('div');
menu.className = 'nj-right-menu';
menu.innerHTML = `
<div class="nj-menu-header">
<h2>📡 南京广播电视台</h2>
<p>${timeStr} · ${NJ_CHANNELS.length}个频道</p>
</div>
<div class="nj-menu-tabs">
<button class="nj-tab-btn ${currentTab === 'tv' ? 'active' : ''}" data-tab="tv">📺 电视 (${NJ_CHANNELS.filter(c => c.type === 'tv').length})</button>
<button class="nj-tab-btn ${currentTab === 'fm' ? 'active' : ''}" data-tab="fm">📻 广播 (${NJ_CHANNELS.filter(c => c.type === 'fm').length})</button>
</div>
<div class="nj-channel-list" id="nj-channel-list"></div>
<div class="nj-menu-footer">
<span>⚡ 点击频道快速切换 | 双击视频全屏</span>
</div>
`;
menu.querySelectorAll('.nj-tab-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
currentTab = e.target.dataset.tab;
updateTabsState();
renderChannelList(currentTab);
});
});
document.body.appendChild(menu);
console.log('菜单已添加到页面');
const toggleBtn = document.createElement('div');
toggleBtn.className = 'nj-menu-toggle';
toggleBtn.innerHTML = '📺';
toggleBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
toggleMenu();
});
document.body.appendChild(toggleBtn);
renderChannelList(currentTab);
}
function toggleMenu() {
const menu = document.querySelector('.nj-right-menu');
const toggle = document.querySelector('.nj-menu-toggle');
if (!menu || !toggle) return;
menuOpen = !menuOpen;
menu.classList.toggle('open', menuOpen);
toggle.classList.toggle('menu-open', menuOpen);
toggle.innerHTML = menuOpen ? '✕' : '📺';
}
function createChannelHint() {
if (document.querySelector('.nj-current-channel-hint')) return;
const channel = getCurrentChannel();
const hint = document.createElement('div');
hint.className = 'nj-current-channel-hint';
hint.textContent = `${channel.icon} ${channel.n.replace(/[📺📻]\s/, '')}`;
document.body.appendChild(hint);
}
function createFullscreenHint() {
if (document.querySelector('.nj-fullscreen-hint')) return;
const hint = document.createElement('div');
hint.className = 'nj-fullscreen-hint';
hint.textContent = '⛶ 双击视频全屏';
document.body.appendChild(hint);
let timeout;
document.addEventListener('mousemove', () => {
hint.classList.remove('hidden');
clearTimeout(timeout);
timeout = setTimeout(() => {
hint.classList.add('hidden');
}, 2000);
});
}
// 广播页面自定义播放器
function createFmPlayer(audio) {
if (document.querySelector('.nj-fm-player')) return;
audioElement = audio;
const channel = getCurrentChannel();
const playerDiv = document.createElement('div');
playerDiv.className = 'nj-fm-player';
playerDiv.innerHTML = `
<div class="nj-fm-background"></div>
<div class="nj-fm-cover ${audio.paused ? '' : 'playing'}">
<span>${channel.icon}</span>
</div>
<div class="nj-fm-info">
<div class="nj-fm-title">${channel.n.replace(/[📺📻]\s/, '')}</div>
<div class="nj-fm-subtitle">南京广播电视台 · 直播中</div>
</div>
<div class="nj-fm-controls">
<button class="nj-fm-btn prev" title="上一个广播">⏮</button>
<button class="nj-fm-btn play-pause">${audio.paused ? '▶' : '⏸'}</button>
<button class="nj-fm-btn next" title="下一个广播">⏭</button>
<div class="nj-fm-volume">
<span class="nj-fm-volume-icon">🔊</span>
<input type="range" class="nj-fm-volume-slider" min="0" max="1" step="0.01" value="${audio.volume}">
</div>
</div>
`;
document.body.appendChild(playerDiv);
fmPlayer = playerDiv;
const playBtn = playerDiv.querySelector('.play-pause');
const prevBtn = playerDiv.querySelector('.prev');
const nextBtn = playerDiv.querySelector('.next');
const volumeSlider = playerDiv.querySelector('.nj-fm-volume-slider');
const cover = playerDiv.querySelector('.nj-fm-cover');
playBtn.addEventListener('click', () => {
if (audio.paused) {
audio.play().then(() => {
playBtn.textContent = '⏸';
cover.classList.add('playing');
}).catch(e => console.log('播放失败', e));
} else {
audio.pause();
playBtn.textContent = '▶';
cover.classList.remove('playing');
}
});
prevBtn.addEventListener('click', () => {
const channels = NJ_CHANNELS.filter(c => c.type === 'fm');
const current = getCurrentChannel();
const index = channels.findIndex(c => c.id === current.id);
const prev = channels[(index - 1 + channels.length) % channels.length];
switchChannel(prev);
});
nextBtn.addEventListener('click', () => {
const channels = NJ_CHANNELS.filter(c => c.type === 'fm');
const current = getCurrentChannel();
const index = channels.findIndex(c => c.id === current.id);
const next = channels[(index + 1) % channels.length];
switchChannel(next);
});
volumeSlider.addEventListener('input', (e) => {
audio.volume = e.target.value;
});
audio.addEventListener('play', () => {
playBtn.textContent = '⏸';
cover.classList.add('playing');
});
audio.addEventListener('pause', () => {
playBtn.textContent = '▶';
cover.classList.remove('playing');
});
audio.addEventListener('volumechange', () => {
volumeSlider.value = audio.volume;
});
}
// 激活当前电视频道高亮
function highlightCurrentTVChannel() {
const searchParams = new URLSearchParams(location.search);
const id = searchParams.get('id');
if (!id) return;
document.querySelectorAll('.tv_list li').forEach(li => {
li.classList.remove('current');
if (li.classList.contains(`tv_c${id}`)) {
li.classList.add('current');
}
});
}
// 为原生频道按钮添加点击事件
function setupNativeChannelButtons() {
document.querySelectorAll('.tv_list li').forEach(li => {
li.removeEventListener('click', handleNativeChannelClick);
li.addEventListener('click', handleNativeChannelClick);
});
}
function handleNativeChannelClick() {
const classes = this.className.split(' ');
const tvClass = classes.find(c => c.startsWith('tv_c'));
if (tvClass) {
const id = tvClass.replace('tv_c', '');
const channel = NJ_CHANNELS.find(c => c.id === id);
if (channel) {
switchChannel(channel);
}
}
}
// 电视页面初始化
function initTVPage() {
console.log('[南京广电] 电视页面初始化');
setTimeout(() => {
setupNativeChannelButtons();
highlightCurrentTVChannel();
const checkVideo = setInterval(() => {
const video = document.querySelector('video');
if (video && !dplayerInitialized) {
dplayerInitialized = true;
console.log('[南京广电] 检测到视频元素');
video.controls = true;
addDoubleClickFullscreen();
clearInterval(checkVideo);
}
}, 500);
setTimeout(() => {
clearInterval(checkVideo);
}, 10000);
}, 2000);
createRightMenu();
createChannelHint();
createFullscreenHint();
}
// 广播页面初始化
function initFMPage() {
console.log('[南京广电] 广播页面初始化');
const checkAudio = setInterval(() => {
const audio = document.getElementById('Html5Video') || document.querySelector('audio') || document.querySelector('video');
if (audio) {
clearInterval(checkAudio);
console.log('[南京广电] 找到音频元素');
audio.controls = false;
audio.style.cssText = 'width:0;height:0;opacity:0;pointer-events:none;position:absolute;';
setTimeout(() => {
audio.play().then(() => {
console.log('音频自动播放成功');
}).catch(e => {
console.log('自动播放失败,等待用户交互');
const clickPlay = () => {
audio.play();
document.removeEventListener('click', clickPlay);
};
document.addEventListener('click', clickPlay, { once: true });
});
}, 500);
createFmPlayer(audio);
}
}, 500);
createRightMenu();
createChannelHint();
}
function addDoubleClickFullscreen() {
const video = document.querySelector('video');
const dplayer = document.getElementById('dplayer');
const container = document.querySelector('.video_a');
const elements = [video, dplayer, container].filter(el => el);
elements.forEach(el => {
if (el) {
el.removeEventListener('dblclick', handleDoubleClick);
el.addEventListener('dblclick', handleDoubleClick);
}
});
}
function handleDoubleClick(e) {
e.preventDefault();
e.stopPropagation();
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement) {
if (document.exitFullscreen) document.exitFullscreen();
else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
} else {
const player = document.querySelector('#dplayer') || document.querySelector('video') || document.querySelector('.video_a');
if (player) {
if (player.requestFullscreen) player.requestFullscreen();
else if (player.webkitRequestFullscreen) player.webkitRequestFullscreen();
else if (player.mozRequestFullScreen) player.mozRequestFullScreen();
}
}
}
// 更新时间
function updateTime() {
const timeDisplay = document.querySelector('.nj-menu-header p');
if (timeDisplay) {
const now = new Date();
const timeStr = now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
timeDisplay.textContent = `${timeStr} · ${NJ_CHANNELS.length}个频道`;
}
const hint = document.querySelector('.nj-current-channel-hint');
if (hint) {
const channel = getCurrentChannel();
hint.textContent = `${channel.icon} ${channel.n.replace(/[📺📻]\s/, '')}`;
}
if (getPageType() === 'tv') {
highlightCurrentTVChannel();
}
}
setInterval(updateTime, 1000);
function init() {
console.log('[南京广电] 脚本启动', location.href);
const pageType = getPageType();
setTimeout(() => {
if (pageType === 'tv') {
initTVPage();
} else {
initFMPage();
}
}, 1000);
}
// 监听页面变化
let lastUrl = location.href;
const observer = new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
console.log('[南京广电] 页面切换:', url);
dplayerInitialized = false;
document.querySelectorAll('.nj-right-menu, .nj-menu-toggle, .nj-current-channel-hint, .nj-fullscreen-hint, .nj-fm-player').forEach(el => el.remove());
setTimeout(init, 1500);
}
});
observer.observe(document, { subtree: true, childList: true });
// 在DOM加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();