- // ==UserScript==
- // @name Bilibili - 优化未登录(不可用)情况下的移动网页端
- // @namespace https://bilibili.com/
- // @version 0.1
- // @description 优化未登录(不可用)情况下的移动网页端的使用体验
- // @license GPL-3.0
- // @author DD1969
- // @match https://m.bilibili.com/*
- // @icon https://www.bilibili.com/favicon.ico
- // @grant none
- // @run-at document-end
- // ==/UserScript==
-
- (async function() {
- 'use strict';
-
- // prevent downloading apk or opening external app
- Object.defineProperty(document, 'hidden', { get: () => true });
- Object.defineProperty(Event.prototype, 'timeStamp', { get: () => NaN });
- const emptyFunction = () => {};
- setInterval(() => {
- if (window.PlayerAgent && window.PlayerAgent.openApp !== emptyFunction) {
- window.PlayerAgent.openApp = emptyFunction;
- }
- }, 500);
-
- // add custom style
- const styleElement = document.createElement('style');
- styleElement.textContent = `
- #app .m-navbar .right .face,
- #app .m-navbar .right .m-nav-openapp,
- .home-float-openapp,
- .caution-dialog,
- .launch-app-btn.m-video-main-launchapp,
- [class*=float-openapp],
- #relateRecomMore,
- .card > .open-app,
- #app .mplayer-widescreen-callapp,
- #app .mplayer-fullscreen-call-app,
- .visible-open-app-btn,
- .share-video-info .title-wrapper .title a.label,
- .share-video-info .title-wrapper .icon-spread,
- .up .interact-wrapper,
- .bottom-tabs,
- .list-view__state,
- .mplayer-control-btn-speed .mplayer-control-dot,
- .mplayer-control-btn-quality .mplayer-control-dot,
- #bilibiliPlayer .mplayer-comment-text,
- .v-card-toapp .card .label,
- .play-page-gotop,
- .natural-main-video .main-cover .play-icon {
- display: none !important;
- }
-
- .m-navbar .right .search {
- width: auto !important;
- height: 42px !important;
- margin-right: 0 !important;
- padding: 12px 0 8px 128px;
- }
-
- .m-search-together .list {
- overflow-x: hidden;
- }
-
- .fixed-module {
- position: relative !important;
- }
-
- .natural-main-video {
- padding-bottom: 24px;
- flex-direction: column;
- }
-
- .natural-main-video .main-cover {
- margin-bottom: 20px;
- width: 100% !important;
- }
-
- .natural-main-video .main-info {
- margin: 0;
- width: 100%;
- }
-
- .natural-main-video .main-info .btn.light {
- margin-top: 20px;
- width: 100%;
- height: 48px;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 16px;
- }
-
- .natural-module > .m-video-related {
- margin-top: 0 !important;
- padding-top: 16px;
- border-top: 1px dashed #AAAAAA;
- }
-
- .bottom-tab > .m-video-related {
- padding-top: 16px;
- }
-
- .v-dialog.natural-dialog:has(.to-see) {
- opacity: 0 !important;
- }
-
- .m-video-player {
- position: relative !important;
- z-index: 999 !important;
- }
-
- .share-video-info {
- margin-top: 56px !important;
- }
-
- .share-video-info .title-name {
- margin-left: 0 !important;
- }
-
- .share-video-info h1.title-text {
- font-weight: bold !important;
- font-size: 16px !important;
- }
-
- .m-footer {
- margin-top: 40px;
- padding-top: 90px;
- border-top: 1px dashed #AAAAAA;
- }
-
- .playback-rate-option-container {
- width: 240px;
- padding: 8px;
- display: flex;
- flex-direction: column;
- align-items: center;
- background-color: #FFFFFF;
- border-radius: 4px;
- user-select: none;
- }
-
- .playback-rate-option {
- width: 100%;
- margin-top: 2px;
- padding: 8px 0;
- color: #FFFFFF;
- background-color: #00AEEC;
- border-top: 1px solid #EEEEEE;
- border-radius: 4px;
- text-align: center;
- }
- `;
- document.head.appendChild(styleElement);
-
- // open home video in new tab
- setInterval(() => {
- const videoCards = Array.from(document.querySelectorAll('.m-home .card-box a.v-card:not(.modified)'));
- for (const card of videoCards) {
- card.classList.add('modified');
- card.setAttribute('target', '_blank');
- }
- }, 1000);
-
- // open searched video in new tab
- setInterval(() => {
- const videoCards = Array.from(document.querySelectorAll('.video-list .card-box .v-card-single:not(.modified)'));
- for (const card of videoCards) {
- const maskElement = document.createElement('div');
- maskElement.style = `
- position: absolute;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100%;
- background-color: #000000;
- opacity: 0;
- `;
- maskElement.addEventListener('click', (e) => {
- if (parseInt(card.dataset.aid) === 0) return;
- e.stopPropagation();
- window.open(`https://m.bilibili.com/video/${av2bv(card.dataset.aid)}`, '_blank');
- });
-
- card.style.position = 'relative';
- card.classList.add('modified');
- card.appendChild(maskElement);
- }
- }, 1000);
-
- // click cancel btn which appeared after clicking video card in search page
- setInterval(() => {
- const openAppDialogCancelBtn = document.querySelector('.v-dialog .open-app-dialog .open-app-dialog-btn.cancel');
- if (openAppDialogCancelBtn) openAppDialogCancelBtn.click();
- }, 100);
-
- // click the "X" mark in the bottom dialog in video page
- const timer4CloseBtn = setInterval(() => {
- const openAppDialogCloseBtn = document.querySelector('.openapp-dialog .dialog-close');
- if (openAppDialogCloseBtn) {
- openAppDialogCloseBtn.click();
- clearInterval(timer4CloseBtn);
- }
- }, 100);
-
- // add publish date
- setInterval(() => {
- const publishDate = document.querySelector('meta[itemprop=datePublished]');
- const authorElement = document.querySelector('.natural-module .main-info .author');
- if (publishDate && authorElement && !authorElement.textContent.includes(' @ ')) {
- authorElement.textContent += ` @ ${publishDate.getAttribute('content')}`;
- }
- }, 500);
-
- // click the "play now" button on the top
- const timer4PlayBtn = setInterval(() => {
- const playNowBtn = document.querySelector('.natural-main-video .main-info .btn.light');
- if (playNowBtn) {
- playNowBtn.onclick = () => {
- const timer4ToSeeBtn = setInterval(() => {
- const toSeeBtn = document.querySelector('.to-see');
- if (toSeeBtn) {
- toSeeBtn.click();
- clearInterval(timer4ToSeeBtn);
- }
- }, 100);
- }
- clearInterval(timer4PlayBtn);
- }
- }, 100);
-
- // open space by clicking author avatar or name
- setInterval(() => {
- const upElement = document.querySelector('.share-video-info .up .face');
- const upID = window?.__INITIAL_STATE__?.video?.upInfo?.card?.mid;
- if (upElement && upID) {
- if (upElement.classList.contains('modified')) return;
- upElement.classList.add('modified');
- upElement.onclick = () => window.open(`https://m.bilibili.com/space/${upID}`, '_blank');
- }
- }, 1000);
-
- // open recommand video
- setInterval(() => {
- const videoCards = Array.from(document.querySelectorAll('.m-video-related .card-box .v-card-toapp:not(.modified)'));
- for (const card of videoCards) {
- card.classList.add('modified');
- card.querySelector('a').onclick = () => window.open(`https://m.bilibili.com/video/${av2bv(card.dataset.aid)}`, '_blank');
- }
- }, 1000);
-
- // open video in space
- setInterval(() => {
- const cards = Array.from(document.querySelectorAll('.dynamic-list .list .cover .card-content .main > [regstring][type="8"]:not(.modified)'));
- for (const card of cards) {
- card.classList.add('modified');
- card.onclick = () => window.open(`https://m.bilibili.com/video/${av2bv(Number(card.id))}`, '_blank');
- }
- }, 1000);
-
- // enable playback rate button
- const timer4PlaybackRateBtn = setInterval(() => {
- const playbackRateBtn = document.querySelector('.mplayer-control-bar .mplayer-control-btn-speed');
- if (playbackRateBtn) {
- playbackRateBtn.onclick = () => {
- const maskElement = document.createElement('div');
- maskElement.style = `
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999999;
- `;
-
- maskElement.innerHTML = `
- <div class="playback-rate-option-container">
- <span style="margin-bottom: 6px; padding: 6px 0;">播放倍速</span>
- <span class="playback-rate-option" data-rate="5">5.0x</span>
- <span class="playback-rate-option" data-rate="3">3.0x</span>
- <span class="playback-rate-option" data-rate="2">2.0x</span>
- <span class="playback-rate-option" data-rate="1.5">1.5x</span>
- <span class="playback-rate-option" data-rate="1">1.0x</span>
- <span class="playback-rate-option" data-rate="0.5">0.5x</span>
- </div>
- `;
-
- maskElement
- .querySelectorAll('.playback-rate-option')
- .forEach(optionElement => optionElement.addEventListener('click', function() {
- const videoElement = document.querySelector('#bilibiliPlayer video');
- if (videoElement) videoElement.playbackRate = parseFloat(this.dataset.rate);
- }));
-
- maskElement.onclick = () => maskElement.remove();
-
- (document.querySelector('#bilibiliPlayer > .mplayer.mplayer-wide') || document.body).appendChild(maskElement);
- }
- clearInterval(timer4PlaybackRateBtn);
- }
- }, 100);
-
- // av ID to bv ID
- function av2bv(avid) {
- const BYTES = ["B", "V", 1, "", "", "", "", "", "", "", "", ""];
- const BV_LEN = BYTES.length;
- const MAX_AID = 1n << 51n;
- const XOR_CODE = 23442827791579n;
- const BASE = 58n;
- const DIGIT_MAP = [0, 1, 2, 9, 7, 5, 6, 4, 8, 3, 10, 11];
- const ALPHABET = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf'.split('');
-
- if(typeof avid !== "bigint") avid = BigInt(avid);
- const bytes = Array.from(BYTES);
- let bv_idx = BV_LEN - 1;
- let tmp = (MAX_AID | avid) ^ XOR_CODE;
- while (tmp !== 0n) {
- let table_idx = tmp % BASE;
- bytes[DIGIT_MAP[Number(bv_idx)]] = ALPHABET[Number(table_idx)];
- tmp /= BASE;
- bv_idx -= 1;
- }
- return bytes.join("");
- }
-
- })();