哔哩哔哩番剧出差助手

为动态页面增加显示哔哩哔哩番剧出差动态功能

当前为 2021-08-28 提交的版本,查看 最新版本

// ==UserScript==
// @name         哔哩哔哩番剧出差助手
// @namespace    bilibili_abroad_assistant
// @version      2.1.1
// @description  为动态页面增加显示哔哩哔哩番剧出差动态功能
// @author       溶酶菌
// @match        *://t.bilibili.com
// @match        *://t.bilibili.com/?*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        GM_addStyle
// @license      MIT
// @run-at       document-idle
// ==/UserScript==
(function () {
  'use strict';
  let loaded = false // 是否已加载
  let showBtn = () => document.querySelector('#show-abroad')
  let hideBtn = () => document.querySelector('#hide-abroad')
  let refreshBtn = () => document.querySelector('#refresh-abroad')
  let backtop = () => document.querySelector("#app > div > div.home-page.f-clear > div.back-top").click()
  let centerPanel = () => document.querySelector("#app > div > div.home-page.f-clear > div.home-container > div > div.center-panel")
  let cardList = () => document.querySelector("#app > div > div.home-page.f-clear > div.home-container > div > div.center-panel > div.card-list")
  let left = () => document.querySelector("#app > div > div.home-page.f-clear > div.home-container > div > div.left-panel > div.adaptive-scroll > div.scroll-content")
  let dynamicsPanel = () => document.querySelector('#dynamics-panel')
  let keywordInput = () => document.querySelector('.space_input')
  let cubeList = () => document.querySelector('.cube-list')
  let bePager = () => document.querySelector('.be-pager')
  let dateFormat = (fmt, date) => {
    let ret;
    const opt = {
      "Y+": date.getFullYear().toString(),        // 年
      "m+": (date.getMonth() + 1).toString(),     // 月
      "d+": date.getDate().toString(),            // 日
      "H+": date.getHours().toString(),           // 时
      "M+": date.getMinutes().toString(),         // 分
      "S+": date.getSeconds().toString()          // 秒
      // 有其他格式化字符需求可以继续添加,必须转化成字符串
    };
    for (let k in opt) {
      ret = new RegExp("(" + k + ")").exec(fmt);
      if (ret) {
        fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
      };
    };
    return fmt;
  }
  let setLoading = (ld) => {
    if (ld) {
      let loadingPanel = document.createElement('div')
      loadingPanel.setAttribute('id', 'loading-panel')
      loadingPanel.classList.add('loading')
      loadingPanel.innerHTML = `<span>正在加载...</span>`
      dynamicsPanel().append(loadingPanel)
    } else {
      document.querySelector('#loading-panel').remove()
    }
  }
  let loadData = function (ps = 12, pn = 1) {
    setLoading(true)
    if (isNaN(pn)) {
      return
    }
    let keyword = keywordInput().value || ''
    fetch(`https://api.bilibili.com/x/space/arc/search?mid=11783021&ps=${ps}&tid=0&pn=${pn}&keyword=${keyword}&order=pubdate&jsonp=jsonp`, {
      method: 'GET',
      credentials: 'include'
    }).then(res => res.json())
      .then(res => {
        setLoading(false)
        if (res.code !== 0) {
          return
        }
        cubeList()?.remove()
        bePager()?.remove()
        let { tlist, vlist } = res.data.list
        let { pn, ps, count } = res.data.page
        let listDom = document.createElement('ul')
        listDom.classList.add('cube-list')
        if (!vlist.length) {
          return
        }
        vlist.forEach(item => {
          let timestamp = new Date(item.created * 1e3) // s -> ms
          let itemDom = document.createElement('li')
          itemDom.classList.add('small-item')
          itemDom.innerHTML = `<a href="//www.bilibili.com/video/${item.bvid}" target="_blank" class="cover">
              <img src="${item.pic}@380w_240h_100Q_1c.webp"
                  alt="${item.title}">
              <span class="length">${item.length}</span>
          </a>
          <a href="//www.bilibili.com/video/${item.bvid}" target="_blank" title="${item.title}"
              class="title">${item.title}</a>
          <div class="meta"><span class="play"><i class="icon"></i>${item.play}
              </span>
              <span class="time" title="${dateFormat('YYYY-mm-dd HH:MM:SS', timestamp)}">
                  <i class="icon"></i>${dateFormat('mm-dd HH:MM', timestamp)}
              </span>
          </div>`
          listDom.append(itemDom)
        })
        dynamicsPanel().append(listDom)
        dynamicsPanel().append(getPageBar(ps, pn, count))
      });
  }

  let getPageBar = (ps, pn, count) => {
    let pageBarDom = document.createElement('ul')
    pageBarDom.classList.add('be-pager')

    let totalPage = Math.floor(count / ps)
    let prePage = pn > 1 ? pn - 1 : undefined
    let nextPage = pn < totalPage ? pn + 1 : undefined
    let pageCurDom = document.createElement('li')
    let pageNextDom = document.createElement('li')
    let pageTotalDom = document.createElement('span')
    let pageElevatorDom = document.createElement('span')

    let firstPageDom = document.createElement('li')
    firstPageDom.classList.add('be-pager-prev')
    firstPageDom.innerHTML = `<a>首页</a>`
    firstPageDom.onclick = () => {
      loadData()
    }
    pageBarDom.append(firstPageDom)

    if (pn > 1) {
      let pagePrev = document.createElement('li')
      pagePrev.classList.add('be-pager-item')
      pagePrev.innerHTML = `<a>${prePage}</a>`
      pagePrev.onclick = () => {
        if (prePage) {
          loadData(ps, prePage)
        }
      }
      pageBarDom.append(pagePrev)
    }

    pageCurDom.classList.add('be-pager-item')
    pageCurDom.classList.add('be-pager-item-active')
    pageCurDom.innerHTML = `<a>${pn}</a>`
    pageBarDom.append(pageCurDom)

    if (pn < totalPage) {
      pageNextDom.classList.add('be-pager-item')
      pageNextDom.innerHTML = `<a>${nextPage}</a>`
      pageNextDom.onclick = () => {
        if (nextPage) {
          loadData(ps, nextPage)
        }
      }
      pageBarDom.append(pageNextDom)
    }

    let lastPageDom = document.createElement('li')
    lastPageDom.classList.add('be-pager-next')
    lastPageDom.innerHTML = `<a>末页</a>`
    lastPageDom.onclick = () => {
      loadData(ps, totalPage)
    }
    pageBarDom.append(lastPageDom)

    pageTotalDom.classList.add('be-pager-total')
    pageTotalDom.innerHTML = ` 共 ${totalPage} 页,</span>`
    pageBarDom.append(pageTotalDom)

    pageElevatorDom.classList.add('be-pager-options-elevator')

    let span = document.createElement('span')
    span.innerText = '跳转至'
    pageElevatorDom.append(span)
    let spaceInput = document.createElement('input')
    spaceInput.classList.add('space_input')
    spaceInput.setAttribute('type', 'num')
    spaceInput.onkeydown = function (event) {
      if (event.key === 'Enter') {
        let value = Number(spaceInput.value)
        if (!isNaN(value)) {
          if (value > totalPage) {
            spaceInput.value = totalPage
            value = totalPage
          }
          loadData(ps, value)
        }
      }
    }
    pageElevatorDom.append(spaceInput)
    span = document.createElement('span')
    span.innerText = '页'
    pageElevatorDom.append(span)
    pageBarDom.append(pageElevatorDom)
    return pageBarDom
  }

  let start = () => {
    if (!centerPanel()) {
      return
    }
    let panel = document.createElement('div')
    panel.id = 'dynamics-panel'
    panel.style.display = 'none'
    panel.style.marginTop = '8px'
    panel.style.backgroundColor = '#FFF'
    centerPanel().append(panel)

    
    const listHeader = document.createElement('div')
    listHeader.classList.add('list-header')
    listHeader.innerHTML = `<div class="g-search search-container"><input type="text" placeholder="搜索视频" class="space_input"><span class="icon search-btn"></span></div>`
    panel.append(listHeader)
    panel.querySelector('.search-btn').onclick = () => {
      loadData()
    }
    panel.querySelector('.space_input').onkeydown = (e) => {
      if (e.key === 'Enter') {
        loadData()
      }
    }

    let actionbar = document.createElement('div')
    actionbar.innerHTML =
      `<div style="margin-top: 8px;border-radius: 4px;position: sticky;top: 8px;background: #FFF;padding: 16px;display: flex;">
        <div class="avatar" style="box-shadow: 0 0 0 1px #f25d8e;border-radius: 22px;height: 38px;width:38px;background-size: 38px 38px;background-image: url(&quot;https://i0.hdslb.com/bfs/face/9f10323503739e676857f06f5e4f5eb323e9f3f2.jpg@96w_96h_100Q_1c.webp&quot;);"></div>
        <div style="margin-left: 11px;">
          <div>哔哩哔哩番剧出差</div>
          <div style="margin-top: 4px;font-size: 12px;color: #00b5e5">
            <span id="show-abroad" style="cursor: pointer">显示</span>
            <span id="hide-abroad" style="cursor: pointer;display: none">隐藏</span>
            <span id="refresh-abroad" style="cursor: pointer;display: none;margin-left: 1em">刷新</span>
          </div>
        </div>
    </div>`

    left().append(actionbar)

    let toggleMode = (show = true) => {
      showBtn().style.display = show ? 'none' : 'inline'
      hideBtn().style.display = show ? 'inline' : 'none'
      refreshBtn().style.display = show ? 'inline' : 'none'
      cardList().style.display = show ? 'none' : 'block'
      dynamicsPanel().style.display = show ? 'block' : 'none'
      backtop()
    }

    showBtn().onclick = () => {
      toggleMode(true)
      if (!loaded) {
        loadData()
        loaded = true
      }
    }
    hideBtn().onclick = () => {
      toggleMode(false)
    }
    refreshBtn().onclick = () => {
      loadData()
      backtop()
    }

  }

  let sleep = function (time) {
    return new Promise((resolve) => setTimeout(resolve, time));
  };

  // 延迟执行,否则可能找不到对应的DOM
  sleep(500).then(() => {
    console.log('哔哩哔哩番剧出差助手运行')
    start()
  })

  //========================================= css
  GM_addStyle(`#dynamics-panel{position:relative;padding:20px;min-height:270px}#dynamics-panel .list-header{padding:0 10px 10px;display:flex;flex-direction:row-reverse}#dynamics-panel .list-header .g-search{position:relative;display:inline-block;width:134px;height:30px;vertical-align:middle}#dynamics-panel .list-header .g-search input{position:absolute;height:30px;width:134px;padding:0 29px 0 10px;line-height:30px;color:#222;font-size:12px;border:1px solid #ccd0d7;border-radius:15px;box-shadow:none;box-sizing:border-box;outline:none}#dynamics-panel .list-header .g-search .search-btn{position:absolute;right:8px;top:0;width:18px;height:30px;background-position:-1111px -81px;cursor:pointer}#dynamics-panel #loading-panel{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255,255,255,0.8);color:#00a1d6;text-align:center;display:flex;justify-content:center;align-items:center}#dynamics-panel .icon{vertical-align:middle;background-repeat:no-repeat;background-image:url(//s1.hdslb.com/bfs/static/jinkela/space/assets/icons.png)}#dynamics-panel a{color:inherit;text-decoration:none;transition:color 0.2s ease, background-color 0.2s ease}#dynamics-panel .i-watchlater{display:none;position:absolute;right:6px;bottom:4px;width:22px;height:22px;z-index:5;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAABT0lEQVQ4je3VMYrCQBTG8b/DWASLNKJgJ1hY2sloZeF2gkeYW+wZvIVXsLBJY5UdtLJLk17EIghCwChukWRxFzSaaLdfMwm8/EgemTclgOl02gEmwAAoky8RsAA+tdbrUoJ+AVZO8G9CoCeJ39Sq1+sopbBtO5e23+8xxrDdbi1gIog/vxAKYNs2Sqn0diBIenoP9X2fIAgyccv66WZZZBXvdjtc18UYkwlfJxM+n8+/1pfBefMPPw4LEZcEQcBqteJ0Or0GrlartFotLpcLnucxm83YbDbFYSEE/X6f4XBIpVLhcDjgOA6u63I8HvPDaRqNBuPxmHa7DcS7cT6f36yXj8IAUkq63S7NZpPlcomUtx9/Ck5Tq9UYjUZ3a976u0UQz9OiCcMwvYwk8XHyYYxBKXU9+p5Grybg4m1Hk9Bar4Ee4JC0JWeixOhprdffE/1yRW/TLMYAAAAASUVORK5CYII=) no-repeat}#dynamics-panel .be-tags-container{position:absolute;top:4px;right:4px}#dynamics-panel .be-tags-container .tag.new-tag{background-color:#42a0c4}#dynamics-panel .be-tags-container .tag{display:inline-block;padding:0 4px;font-size:10px;color:#fff;text-align:center;line-height:14px;border-radius:2px;margin-left:4px}#dynamics-panel .cube-list{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%;box-sizing:border-box}#dynamics-panel .cube-list .clearfix{display:block}#dynamics-panel .cube-list .small-item{display:inline-block;width:160px;position:relative;margin:0 0 3px;padding:10px;cursor:pointer}#dynamics-panel .cube-list .small-item .length{background:#111;background:rgba(0,0,0,0.5);border-radius:5px 0 0 0;color:#fff;line-height:20px;transition:top 0.2s ease;padding:0 6px;position:absolute;right:0;bottom:0}#dynamics-panel .cube-list .small-item .cover{background:url(//s1.hdslb.com/bfs/static/jinkela/space/assets/video-placeholder.png) 50%;background-size:cover;border-radius:4px;display:block;width:160px;height:100px;overflow:hidden;position:relative}#dynamics-panel .cube-list .small-item img{border-radius:4px;display:block;width:160px;height:100px}#dynamics-panel .cube-list .small-item .title{display:block;line-height:20px;height:38px;margin-top:6px;overflow:hidden}#dynamics-panel .cube-list .small-item .meta{color:#999;white-space:nowrap;font-size:0;margin-top:6px;height:14px;line-height:14px}#dynamics-panel .cube-list .small-item .meta>span{display:inline-block;white-space:nowrap;height:14px;line-height:14px;font-size:12px;overflow:hidden}#dynamics-panel .cube-list .small-item .meta>span .icon{width:16px;height:14px;vertical-align:sub}#dynamics-panel .cube-list .small-item .meta>span:first-child{width:72px}#dynamics-panel .cube-list .small-item .play .icon{background-position:-280px -25px;display:inline-block}#dynamics-panel .cube-list .small-item .time .icon{background-position:-280px -474px;display:inline-block}#dynamics-panel .cube-list a:hover{color:#00a1d6}#dynamics-panel .cube-list a,#dynamics-panel .cube-list abbr,#dynamics-panel .cube-list acronym,#dynamics-panel .cube-list address,#dynamics-panel .cube-list applet,#dynamics-panel .cube-list article,#dynamics-panel .cube-list aside,#dynamics-panel .cube-list audio,#dynamics-panel .cube-list b,#dynamics-panel .cube-list big,#dynamics-panel .cube-list blockquote,#dynamics-panel .cube-list body,#dynamics-panel .cube-list canvas,#dynamics-panel .cube-list caption,#dynamics-panel .cube-list center,#dynamics-panel .cube-list cite,#dynamics-panel .cube-list code,#dynamics-panel .cube-list dd,#dynamics-panel .cube-list del,#dynamics-panel .cube-list details,#dynamics-panel .cube-list dfn,#dynamics-panel .cube-list div,#dynamics-panel .cube-list dl,#dynamics-panel .cube-list dt,#dynamics-panel .cube-list em,#dynamics-panel .cube-list embed,#dynamics-panel .cube-list fieldset,#dynamics-panel .cube-list figcaption,#dynamics-panel .cube-list figure,#dynamics-panel .cube-list footer,#dynamics-panel .cube-list form,#dynamics-panel .cube-list h1,#dynamics-panel .cube-list h2,#dynamics-panel .cube-list h3,#dynamics-panel .cube-list h4,#dynamics-panel .cube-list h5,#dynamics-panel .cube-list h6,#dynamics-panel .cube-list header,#dynamics-panel .cube-list hgroup,#dynamics-panel .cube-list html,#dynamics-panel .cube-list i,#dynamics-panel .cube-list iframe,#dynamics-panel .cube-list img,#dynamics-panel .cube-list ins,#dynamics-panel .cube-list kbd,#dynamics-panel .cube-list label,#dynamics-panel .cube-list legend,#dynamics-panel .cube-list li,#dynamics-panel .cube-list mark,#dynamics-panel .cube-list menu,#dynamics-panel .cube-list nav,#dynamics-panel .cube-list object,#dynamics-panel .cube-list ol,#dynamics-panel .cube-list output,#dynamics-panel .cube-list p,#dynamics-panel .cube-list pre,#dynamics-panel .cube-list q,#dynamics-panel .cube-list ruby,#dynamics-panel .cube-list s,#dynamics-panel .cube-list samp,#dynamics-panel .cube-list section,#dynamics-panel .cube-list small,#dynamics-panel .cube-list span,#dynamics-panel .cube-list strike,#dynamics-panel .cube-list strong,#dynamics-panel .cube-list sub,#dynamics-panel .cube-list summary,#dynamics-panel .cube-list sup,#dynamics-panel .cube-list table,#dynamics-panel .cube-list tbody,#dynamics-panel .cube-list td,#dynamics-panel .cube-list tfoot,#dynamics-panel .cube-list th,#dynamics-panel .cube-list thead,#dynamics-panel .cube-list time,#dynamics-panel .cube-list tr,#dynamics-panel .cube-list tt,#dynamics-panel .cube-list u,#dynamics-panel .cube-list ul,#dynamics-panel .cube-list var,#dynamics-panel .cube-list video{margin:0;padding:0;border:0;vertical-align:baseline;word-break:break-word}#dynamics-panel .be-pager{user-select:none;padding:15px 0;text-align:center}#dynamics-panel .be-pager-disabled{display:none}#dynamics-panel .be-pager-next,#dynamics-panel .be-pager-prev{padding:0 14px;border:1px solid #d7dde4;border-radius:4px;background-color:#fff}#dynamics-panel .be-pager-item{display:inline-block;line-height:38px;padding:0 15px;margin-right:4px;text-align:center;list-style:none;background-color:#fff;-ms-user-select:none;user-select:none;cursor:pointer;font-family:Arial;font-size:14px;border:1px solid #d7dde4;border-radius:4px;transition:all 0.2s ease-in-out}#dynamics-panel .be-pager-item-jump-next,#dynamics-panel .be-pager-item-jump-prev,#dynamics-panel .be-pager-next,#dynamics-panel .be-pager-prev{display:inline-block;font-size:14px;line-height:38px;list-style:none;text-align:center;cursor:pointer;color:#666;font-family:Arial;transition:all 0.2s ease-in-out}#dynamics-panel .be-pager-next,#dynamics-panel .be-pager-prev{padding:0 14px;border:1px solid #d7dde4;border-radius:4px;background-color:#fff}#dynamics-panel .be-pager-prev{margin-right:8px}#dynamics-panel .be-pager-item a{text-decoration:none;color:#657180}#dynamics-panel .be-pager-item-active{background-color:#00a1d6;border-color:#00a1d6}#dynamics-panel .be-pager-item-active:hover a,#dynamics-panel .be-pager-item-active a{color:#fff}#dynamics-panel .be-pager-item-active:hover a,#dynamics-panel .be-pager-item-active a{color:#fff}#dynamics-panel .be-pager-total{display:inline-block;height:32px;line-height:32px;margin-left:30px;color:#99a2aa}#dynamics-panel .be-pager-options-elevator{display:inline-block;height:32px;line-height:32px;color:#99a2aa}#dynamics-panel .be-pager-options-elevator input{border-radius:4px;margin:0 8px;width:50px;outline:none}#dynamics-panel .space_input{line-height:28px;height:28px;padding:0 10px;transition:all 0.3s ease;vertical-align:top;border:1px solid #ccd0d7;border-radius:0}
`)
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址