Greasy Fork

Greasy Fork is available in English.

哔哩哔哩番剧出差助手

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

当前为 2022-04-11 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         哔哩哔哩番剧出差助手
// @namespace    bilibili_abroad_assistant
// @version      2.2.0
// @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(".bili-backtop").click()
  let centerPanel = () => document.querySelector("#app > div.bili-dyn-home--member > main")
  let cardList = () => document.querySelectorAll("#app > div.bili-dyn-home--member > main > section")
  let left = () => document.querySelector("#app > div.bili-dyn-home--member > aside.left")
  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.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 style="font-size: 14px">哔哩哔哩番剧出差</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>`

    // let sticky = left().querySelector('.sticky')
    // if(!sticky) {
    //   sticky = document.createElement('section')
    //   sticky.classList.add("sticky")
    //   left().append(sticky)
    // }
    // sticky.append(actionbar)
    left().querySelector("section").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().forEach(item => {
        item.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;font-size:14px}#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;font-size:12px;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}
`)
})();