huangmin1111 发表于 2026-3-14 22:04

南京广播电视台油猴脚本

本帖最后由 huangmin1111 于 2026-3-15 10:30 编辑

南京广播电视台:https://www.nbs.cn/live/,这个脚本再次修改,终于接近完美了。
请各位测试下。






// ==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,
      , , ,
      iframe:not():not(),
      .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;
    }

    // 切换频道
    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(/[&#128250;&#128251;]\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>&#128225; 南京广播电视台</h2>
                <p>${timeStr} · ${NJ_CHANNELS.length}个频道</p>
            </div>
            <div class="nj-menu-tabs">
                <button class="nj-tab-btn ${currentTab === 'tv' ? 'active' : ''}" data-tab="tv">&#128250; 电视 (${NJ_CHANNELS.filter(c => c.type === 'tv').length})</button>
                <button class="nj-tab-btn ${currentTab === 'fm' ? 'active' : ''}" data-tab="fm">&#128251; 广播 (${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 = '&#128250;';
      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 ? '✕' : '&#128250;';
    }

    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(/[&#128250;&#128251;]\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(/[&#128250;&#128251;]\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">&#128266;</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 = .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(/[&#128250;&#128251;]\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();
    }
})();

Mi3na4 发表于 2026-3-15 12:07

專注于地方台與廣播,這個腳本有計劃加上其他地方台嗎。
想來央視網頁和學習強國軟件都有看廣電和聽廣播的說

huangmin1111 发表于 2026-3-15 11:20

已重新修改脚本,基本上没问题了。

梅球王 发表于 2026-3-15 11:24

本帖最后由 beyond0729 于 2026-3-15 15:35 编辑

感谢大佬分享,不知道有没有时间看下河南的有些节目隐藏了

男生 发表于 2026-3-15 11:30

一般我都是手机下载电视直播软件。

戰龍在野 发表于 2026-3-15 12:37

老大,怎么使用呢,谢谢

easonrose 发表于 2026-3-15 13:22

有没有安卓电视版

cnmi 发表于 2026-3-15 13:56

电视有什么好用的直播软件

daymissed 发表于 2026-3-15 15:02

谢谢分享,测试一下感觉速度还可以。

xxx123444 发表于 2026-3-15 16:16

有机会其他电视台吗?
页: [1] 2
查看完整版本: 南京广播电视台油猴脚本