Merge pull request #8 from the1812/preview

Update to 1.5.22
This commit is contained in:
Grant Howard 2018-10-28 14:46:23 +08:00 committed by GitHub
commit a2bf2cf7b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 2453 additions and 720 deletions

View File

@ -1,29 +1,23 @@
# Bilibili-Evolved
增强哔哩哔哩Web端体验的油猴脚本.
增强哔哩哔哩Web端体验的油猴脚本: 修复界面瑕疵, 删除广告, 使用夜间模式浏览, 下载视频或视频封面, 以及增加对触屏设备的支持等.
- [安装](#安装)
- [了解所有功能](#功能概览)
- [浏览设置项](#设置)
- [浏览器兼容性](#兼容性)
- [版本历史与更新日志](https://github.com/the1812/Bilibili-Evolved/releases)
# 安装
需要浏览器拥有[Tampermonkey](https://tampermonkey.net/)或同类插件.
[![正式版](https://img.shields.io/badge/正式版-🌸-green.svg?style=flat-square&colorB=009688)](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.user.js)
正式发布的版本, 最稳定, 更新频率较低.
[![预览版](https://img.shields.io/badge/预览版-🍺-yellow.svg?style=flat-square&colorB=607D8B)](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview.user.js)
新增内容测试的地方, 更新频率高, 但功能不稳定.
[![离线版](https://img.shields.io/badge/离线版-👻-blue.svg?style=flat-square)](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.offline.user.js)
内置所有依赖项, 体积较大, 可以减少GitHub服务器不稳定的影响. 由于任何依赖项更新后此脚本也需更新, 所以更新频率会高于正式版.
[![预览离线版](https://img.shields.io/badge/预览离线版-🌟-blue.svg?style=flat-square&colorB=F06292)](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview-offline.user.js)
兼备预览版和离线版的特点.
[正式版](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.user.js) | [预览版](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview.user.js) | [离线版](https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview.user.js) | [预览离线版](https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.offline.user.js)
----- | ----- | ----- | -----
正式发布的版本, 最稳定, 更新频率较低. | 新增内容测试的地方, 更新频率高, 但功能不稳定. | 内置所有依赖项, 体积较大, 更新频率高于正式版. | 兼备预览版和离线版的特点.
> 某些破坏性的大更新会使旧版脚本**完全**无法工作, 请及时检查更新.
# 设置
脚本启用后, 在网页左侧中央会有一个齿轮图标, 点击即可打开设置.
设置项的说明见功能概览一节.
设置项的说明见[功能概览](#功能概览)一节.
**设置保存后, 需要刷新网页才能生效.**
![设置](images/gui-settings.png)
@ -102,7 +96,7 @@
#### 启用后
![调整](images/override-navbar.png)
#### 移除横幅
在搜索框位置调整启用的时候, 还可以使用此功能移除顶部横幅.
在搜索栏置顶启用的时候, 还可以使用此功能移除顶部横幅.
##### 启用前
![不移除](images/override-navbar.png)
##### 启用后
@ -110,7 +104,10 @@
### 强制宽屏
对主站强制使用宽屏样式, 默认将在宽度达到`1368px`时启用. 这个触发宽度可以在设置中更改为任何有效的CSS宽度值.
> 原有的宽屏样式会在宽度超过`1400px`时使用, 如果将触发宽度设为大于`1400px`的值实际上没有意义.
#### 启用前
![默认布局](images/force-wide-before.png)
#### 启用后
![宽屏布局](images/force-wide-after.png)
## 工具
### 删除广告
@ -132,13 +129,24 @@
## 视频与直播
### 下载视频(实验性)
在视频播放页面中, `设置`→`视频与直播`下会出现下载视频按钮, 点击可以选择清晰度并下载.
由于JavaScript的单线程限制, 下载速度可能不是很快, 如果你更喜欢使用其他的多线程下载软件, 可以在选择清晰度后选择`复制链接`. **下载时的请求Header必须包含`Origin=https://www.bilibili.com`和`Referer=当前视频网址`**
> 目前此功能只支持普通视频, 对番剧和电影无效. 下载后的格式通常为`.flv`, 若需要`.mp4`格式则要手动用其他软件转换.
> **分段**的视频会把所有视频打包成`.zip`格式.
> 能够下载的清晰度取决于当前登录的账号, 例如`高清 1080P60`需要已登录大会员账号.
![下载视频按钮](images/download-video.png)
### 查看封面
在视频播放页面/直播间中, `设置`→`视频与直播`下会出现查看封面按钮, 点击可以查看或保存封面.
在视频播放页面/直播间中, `设置`→`视频与直播`下会出现查看封面按钮, 点击可以查看或保存封面. (其实还可以看专栏的封面, 不过专栏的封面本来就显示在标题上方了)
![查看封面按钮](images/view-cover-button.png)
### 自动展开弹幕列表
新版播放页面中, 弹幕列表默认收起以显示推荐的其他视频. 启用此功能可在每次加载视频时自动展开弹幕列表.
### 缩放看板娘
根据屏幕DPI缩放看板娘的大小以提高像素的清晰度.
根据屏幕DPI缩放看板娘的大小以提高像素的清晰度, DPI缩放为100%的用户可以忽略此选项.
### 删除直播水印
删除观看直播时角落的水印.
### 删除视频标题层
@ -183,6 +191,8 @@
![消息](images/toast.png)
### 模糊设置面板背景
使设置面板的内容区半透明并模糊后方图像.
#### 效果对比
![效果对比](images/gui-settings-blur.png)
### 启用缓存
使用缓存以提高脚本的加载速度, 此选项只对非离线版有效.
@ -199,4 +209,6 @@
- 顶栏触摸体验不佳.
- 触摸功能需要手动在`about:flags`中开启.
## ![Safari:未知](https://img.shields.io/badge/Safari-未知-lightgrey.svg?style=flat-square&colorB=323232)
尚未在Safari中测试.
- 尚未在Safari中测试.
[返回顶部](#Bilibili-Evolved)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,10 @@
// ==UserScript==
// @name Bilibili Evolved (Preview)
// @version 1.5.10
// @description 增强哔哩哔哩Web端体验. (预览版分支)
// @version 1.5.22
// @description 增强哔哩哔哩Web端体验(预览版分支): 修复界面瑕疵, 删除广告, 使用夜间模式浏览, 下载视频或视频封面, 以及增加对触屏设备的支持等.
// @author Grant Howard, Coulomb-G
// @copyright 2018, Grant Howrad (https://github.com/the1812)
// @license MIT
// @match *://*.bilibili.com/*
// @match *://*.bilibili.com
// @run-at document-end
@ -14,7 +16,10 @@
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addValueChangeListener
// @grant GM_setClipboard
// @grant GM_info
// @require https://code.jquery.com/jquery-3.2.1.min.js
// @require https://cdn.bootcss.com/jszip/3.1.5/jszip.min.js
// @icon https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/images/logo.png
// ==/UserScript==
(self$ =>
@ -56,8 +61,10 @@
notifyNewVersion: true,
clearCache: true,
fixFullscreen: false,
latestVersionLink: "https://github.com/the1812/Bilibili-Evolved/raw/preview/bilibili-evolved.preview.user.js",
currentVersion: "1.5.10"
downloadVideo: true,
about: false,
latestVersionLink: GM_info.script.updateURL,
currentVersion: GM_info.script.version
};
function loadSettings()
{
@ -86,129 +93,348 @@
}
function loadResources()
{
Resource.root = "https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/";
Resource.all = {
style: new Resource("min/style.min.scss", 1),
oldStyle: new Resource("min/old.min.scss", 1),
scrollbarStyle: new Resource("min/scrollbar.min.css", 1),
darkStyle: new Resource("min/dark.min.scss", 2),
darkStyleImportant: new Resource("min/dark-important.min.scss"),
darkStyleNavBar: new Resource("min/dark-navbar.min.scss"),
touchPlayerStyle: new Resource("min/touch-player.min.scss", 3),
navbarOverrideStyle: new Resource("min/override-navbar.min.css", 4),
noBannerStyle: new Resource("min/no-banner.min.css", 5),
removeAdsStyle: new Resource("min/remove-promotions.min.css", 6),
guiSettingsStyle: new Resource("min/gui-settings.min.scss", 0),
fullTweetsTitleStyle: new Resource("min/full-tweets-title.min.css", 7),
imageViewerStyle: new Resource("min/image-viewer.min.scss", 8),
toastStyle: new Resource("min/toast.min.scss", 9),
blurVideoControlStyle: new Resource("min/blur-video-control.min.css", 10),
forceWideStyle: new Resource("min/force-wide.min.scss"),
guiSettingsDom: new Resource("min/gui-settings.min.html"),
imageViewerDom: new Resource("min/image-viewer.min.html"),
latestVersion: new Resource("version.txt"),
guiSettings: new Resource("min/gui-settings.min.js"),
useDarkStyle: new Resource("min/dark-styles.min.js"),
useNewStyle: new Resource("min/new-styles.min.js"),
overrideNavBar: new Resource("min/override-navbar.min.js"),
touchNavBar: new Resource("min/touch-navbar.min.js"),
touchVideoPlayer: new Resource("min/touch-player.min.js"),
expandDanmakuList: new Resource("min/expand-danmaku.min.js"),
removeAds: new Resource("min/remove-promotions.min.js"),
watchLaterRedirect: new Resource("min/watchlater.min.js"),
hideTopSearch: new Resource("min/hide-top-search.min.js"),
harunaScale: new Resource("min/haruna-scale.min.js"),
removeLiveWatermark: new Resource("min/remove-watermark.min.js"),
fullTweetsTitle: new Resource("min/full-tweets-title.min.js"),
viewCover: new Resource("min/view-cover.min.js"),
notifyNewVersion: new Resource("min/notify-new-version.min.js"),
toast: new Resource("min/toast.min.js"),
removeVideoTopMask: new Resource("min/remove-top-mask.min.js"),
blurVideoControl: new Resource("min/blur-video-control.min.js"),
darkSchedule: new Resource("min/dark-schedule.min.js"),
forceWide: new Resource("min/force-wide.min.js"),
clearCache: new Resource("min/clear-cache.min.js")
const resouceManifest = {
style: {
path: "min/style.min.scss",
order: 1
},
oldStyle: {
path: "min/old.min.scss",
order: 1
},
scrollbarStyle: {
path: "min/scrollbar.min.css",
order: 1
},
darkStyle: {
path: "min/dark.min.scss",
order: 2
},
darkStyleImportant: {
path: "min/dark-important.min.scss"
},
darkStyleNavBar: {
path: "min/dark-navbar.min.scss"
},
touchPlayerStyle: {
path: "min/touch-player.min.scss",
order: 3
},
navbarOverrideStyle: {
path: "min/override-navbar.min.css",
order: 4
},
noBannerStyle: {
path: "min/no-banner.min.css",
order: 5
},
removeAdsStyle: {
path: "min/remove-promotions.min.css",
order: 6
},
guiSettingsStyle: {
path: "min/gui-settings.min.scss",
order: 0
},
fullTweetsTitleStyle: {
path: "min/full-tweets-title.min.css",
order: 7
},
imageViewerStyle: {
path: "min/image-viewer.min.scss",
order: 8
},
toastStyle: {
path: "min/toast.min.scss",
order: 9
},
blurVideoControlStyle: {
path: "min/blur-video-control.min.css",
order: 10
},
forceWideStyle: {
path: "min/force-wide.min.scss"
},
downloadVideoStyle: {
path: "min/download-video.min.scss"
},
guiSettingsDom: {
path: "min/gui-settings.min.html"
},
imageViewerDom: {
path: "min/image-viewer.min.html"
},
downloadVideoDom: {
path: "min/download-video.min.html"
},
latestVersion: {
path: "version.txt"
},
guiSettings: {
path: "min/gui-settings.min.js",
dependencies: [
"guiSettingsDom",
"guiSettingsStyle"
],
displayNames: {
guiSettings: "设置",
blurSettingsPanel: "模糊设置面板背景"
}
},
useDarkStyle: {
path: "min/dark-styles.min.js",
dependencies: [
"darkStyle",
"darkStyleImportant",
"darkStyleNavBar",
"scrollbarStyle"
],
displayNames: {
useDarkStyle: "夜间模式"
}
},
useNewStyle: {
path: "min/new-styles.min.js",
dependencies: [
"style",
"oldStyle",
"scrollbarStyle"
],
displayNames: {
useNewStyle: "样式调整",
blurBackgroundOpacity: "顶栏(对横幅)不透明度"
}
},
overrideNavBar: {
path: "min/override-navbar.min.js",
dependencies: [
"navbarOverrideStyle",
"noBannerStyle"
],
displayNames: {
overrideNavBar: "搜索栏置顶",
showBanner: "显示顶部横幅"
}
},
touchNavBar: {
path: "min/touch-navbar.min.js",
displayNames: {
touchNavBar: "顶栏触摸优化"
}
},
touchVideoPlayer: {
path: "min/touch-player.min.js",
dependencies: [
"touchPlayerStyle"
],
displayNames: {
touchVideoPlayer: "播放器触摸支持",
touchVideoPlayerAnimation: "启用实验性动画效果",
touchVideoPlayerDoubleTapControl: "启用双击控制"
}
},
expandDanmakuList: {
path: "min/expand-danmaku.min.js",
displayNames: {
expandDanmakuList: "自动展开弹幕列表"
}
},
removeAds: {
path: "min/remove-promotions.min.js",
dependencies: [
"removeAdsStyle"
],
displayNames: {
removeAds: "删除广告"
}
},
watchLaterRedirect: {
path: "min/watchlater.min.js",
displayNames: {
watchLaterRedirect: "稍后再看重定向"
}
},
hideTopSearch: {
path: "min/hide-top-search.min.js",
displayNames: {
hideTopSearch: "隐藏搜索推荐"
}
},
harunaScale: {
path: "min/haruna-scale.min.js",
displayNames: {
harunaScale: "缩放看板娘"
}
},
removeLiveWatermark: {
path: "min/remove-watermark.min.js",
displayNames: {
removeLiveWatermark: "删除直播水印"
}
},
fullTweetsTitle: {
path: "min/full-tweets-title.min.js",
dependencies: [
"fullTweetsTitleStyle"
],
displayNames: {
fullTweetsTitle: "展开动态标题"
}
},
viewCover: {
path: "min/view-cover.min.js",
dependencies: [
"imageViewerDom",
"imageViewerStyle"
],
displayNames: {
viewCover: "查看封面"
}
},
notifyNewVersion: {
path: "min/notify-new-version.min.js",
dependencies: [
"latestVersion"
],
displayNames: {
notifyNewVersion: "检查更新"
}
},
toast: {
path: "min/toast.min.js",
dependencies: [
"toastStyle"
],
displayNames: {
toast: "显示消息"
}
},
removeVideoTopMask: {
path: "min/remove-top-mask.min.js",
displayNames: {
removeVideoTopMask: "删除视频标题层"
}
},
blurVideoControl: {
path: "min/blur-video-control.min.js",
dependencies: [
"blurVideoControlStyle"
],
displayNames: {
blurVideoControl: "模糊视频控制栏背景"
}
},
darkSchedule: {
path: "min/dark-schedule.min.js",
displayNames: {
darkSchedule: "夜间模式计划时段",
darkScheduleStart: "起始时间",
darkScheduleEnd: "结束时间"
}
},
forceWide: {
path: "min/force-wide.min.js",
dependencies: [
"forceWideStyle"
],
displayNames: {
forceWide: "强制宽屏",
forceWideMinWidth: "触发宽度"
}
},
clearCache: {
path: "min/clear-cache.min.js",
displayNames: {
useCache: "启用缓存"
}
},
downloadVideo: {
path: "min/download-video.min.js",
dependencies: [
"downloadVideoDom",
"downloadVideoStyle",
"videoInfo"
]
},
videoInfo: {
path: "min/video-info.min.js"
},
aboutDom: {
path: "min/about.min.html"
},
aboutStyle: {
path: "min/about.min.scss"
},
about: {
path: "min/about.min.js",
dependencies: [
"aboutDom",
"aboutStyle"
]
}
};
(function ()
Resource.root = "https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/";
Resource.all = {};
Resource.displayNames = {};
for (const [key, data] of Object.entries(resouceManifest))
{
this.guiSettings.dependencies = [
this.guiSettingsDom,
this.guiSettingsStyle
];
this.useDarkStyle.dependencies = [
this.darkStyle,
this.darkStyleImportant,
this.darkStyleNavBar,
this.scrollbarStyle
];
this.useNewStyle.dependencies = [
this.style,
this.oldStyle,
this.scrollbarStyle
];
this.overrideNavBar.dependencies = [
this.navbarOverrideStyle,
this.noBannerStyle
];
this.touchVideoPlayer.dependencies = [
this.touchPlayerStyle
];
this.removeAds.dependencies = [
this.removeAdsStyle
];
this.fullTweetsTitle.dependencies = [
this.fullTweetsTitleStyle
];
this.viewCover.dependencies = [
this.imageViewerDom,
this.imageViewerStyle
];
this.notifyNewVersion.dependencies = [
this.latestVersion
];
this.toast.dependencies = [
this.toastStyle
];
this.blurVideoControl.dependencies = [
this.blurVideoControlStyle
];
this.forceWide.dependencies = [
this.forceWideStyle
];
}).apply(Resource.all);
(function ()
const resource = new Resource(data.path, data.order);
resource.key = key;
if (data.displayNames)
{
resource.displayName = data.displayNames[key];
Object.assign(Resource.displayNames, data.displayNames);
}
Resource.all[key] = resource;
}
for (const [key, data] of Object.entries(resouceManifest))
{
this.guiSettings.displayName = "设置";
this.useDarkStyle.displayName = "夜间模式";
this.useNewStyle.displayName = "样式调整";
this.overrideNavBar.displayName = "搜索栏置顶";
this.touchNavBar.displayName = "顶栏触摸优化";
this.touchVideoPlayer.displayName = "播放器触摸支持";
this.expandDanmakuList.displayName = "自动展开弹幕列表";
this.removeAds.displayName = "删除广告";
this.watchLaterRedirect.displayName = "稍后再看重定向";
this.hideTopSearch.displayName = "隐藏搜索推荐";
this.harunaScale.displayName = "缩放看板娘";
this.removeLiveWatermark.displayName = "删除直播水印";
this.fullTweetsTitle.displayName = "展开动态标题";
this.viewCover.displayName = "查看封面";
this.notifyNewVersion.displayName = "新版本提醒";
this.toast.displayName = "显示消息";
this.removeVideoTopMask.displayName = "删除视频标题层";
this.blurVideoControl.displayName = "模糊视频控制栏背景";
this.darkSchedule.displayName = "夜间模式计划时段";
this.forceWide.displayName = "强制宽屏";
}).apply(Resource.all);
if (data.dependencies)
{
Resource.all[key].dependencies = data.dependencies.map(name => Resource.all[name]);
}
}
}
function downloadText(url, load, error)
{
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () => load && load(xhr.responseText));
xhr.addEventListener("error", () => error && error(xhr.responseText));
xhr.open("GET", url);
xhr.send();
if (load) // callback
{
xhr.addEventListener("load", () => load && load(xhr.responseText));
xhr.addEventListener("error", () => error && error(xhr.responseText));
xhr.send();
}
else
{
return new Promise((resolve, reject) =>
{
xhr.addEventListener("load", () => resolve(xhr.responseText));
xhr.addEventListener("error", () => reject(xhr.responseText));
xhr.send();
});
}
}
function fixed(number, precision = 1)
{
const str = number.toString();
const index = str.indexOf(".");
if (index !== -1)
{
if (str.length - index > precision + 1)
{
return str.substring(0, index + precision + 1);
}
else
{
return str;
}
}
else
{
return str + ".0";
}
}
// Placeholder class for Toast
class Toast
@ -561,17 +787,19 @@
{
return new ResourceType("html", html =>
{
const keys = Object.keys(Resource.all).filter(key => Resource.all[key].displayName);
for (const key of keys)
for (const [key, name] of Object.entries(Resource.displayNames))
{
html = html
.replace(new RegExp(`(<checkbox\\s*?indent=".+?"\\s*?key="${key}"\\s*?dependencies=".*?">)[^\\0]*?(</checkbox>)`, "g"),
`$1${Resource.all[key].displayName}$2`);
html = html.replace(new RegExp(`(<(.+)\\s*?indent="[\\d]+?"\\s*?key="${key}"\\s*?dependencies=".*?">)[^\\0]*?(</\\2>)`, "g"),
`$1${name}$3`);
}
return html
.replace(/<category>([^\0]*?)<\/category>/g, `
return html.replace(/<category>([^\0]*?)<\/category>/g, `
<li class="indent-center category">
<span class="settings-category">$1</span>
<span class="settings-category">
$1
<i class="settings-category-arrow"></i>
</span>
</li>
<li class="indent-center widgets-container" category-name="$1">
</li>
`).replace(/<checkbox\s*?indent="(.+?)"\s*?key="(.+?)"\s*?dependencies="(.*?)">([^\0]*?)<\/checkbox>/g, `
<li class="indent-$1">
@ -612,16 +840,13 @@
{
return this.text !== null;
}
get key()
{
return Object.keys(Resource.all).find(k => Resource.all[k] === this);
}
constructor(url, priority)
{
this.url = Resource.root + url;
this.dependencies = [];
this.priority = priority;
this.text = null;
this.key = null;
this.type = ResourceType.fromUrl(url);
this.displayName = "";
}
@ -779,6 +1004,9 @@
return null;
}
const promise = resource.download();
resource.dependencies
.filter(it => it.type.name === "script")
.forEach(it => this.fetchByKey(it.key));
return new Promise(resolve =>
{
promise.then(text =>
@ -854,6 +1082,10 @@
{
panel.find(info.before()).before(info.content);
}
else if (info.category)
{
panel.find(`.widgets-container[category-name=${info.category}]`).append(info.content);
}
if (info.success)
{

View File

@ -1,8 +1,10 @@
// ==UserScript==
// @name Bilibili Evolved
// @version 1.5.10
// @description 增强哔哩哔哩Web端体验.
// @version 1.5.22
// @description 增强哔哩哔哩Web端体验: 修复界面瑕疵, 删除广告, 使用夜间模式浏览, 下载视频或视频封面, 以及增加对触屏设备的支持等.
// @author Grant Howard, Coulomb-G
// @copyright 2018, Grant Howrad (https://github.com/the1812)
// @license MIT
// @match *://*.bilibili.com/*
// @match *://*.bilibili.com
// @run-at document-end
@ -14,7 +16,10 @@
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addValueChangeListener
// @grant GM_setClipboard
// @grant GM_info
// @require https://code.jquery.com/jquery-3.2.1.min.js
// @require https://cdn.bootcss.com/jszip/3.1.5/jszip.min.js
// @icon https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/images/logo.png
// ==/UserScript==
(self$ =>
@ -56,8 +61,10 @@
notifyNewVersion: true,
clearCache: true,
fixFullscreen: false,
latestVersionLink: "https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.user.js",
currentVersion: "1.5.10"
downloadVideo: true,
about: false,
latestVersionLink: GM_info.script.updateURL,
currentVersion: GM_info.script.version
};
function loadSettings()
{
@ -86,129 +93,348 @@
}
function loadResources()
{
Resource.root = "https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/";
Resource.all = {
style: new Resource("min/style.min.scss", 1),
oldStyle: new Resource("min/old.min.scss", 1),
scrollbarStyle: new Resource("min/scrollbar.min.css", 1),
darkStyle: new Resource("min/dark.min.scss", 2),
darkStyleImportant: new Resource("min/dark-important.min.scss"),
darkStyleNavBar: new Resource("min/dark-navbar.min.scss"),
touchPlayerStyle: new Resource("min/touch-player.min.scss", 3),
navbarOverrideStyle: new Resource("min/override-navbar.min.css", 4),
noBannerStyle: new Resource("min/no-banner.min.css", 5),
removeAdsStyle: new Resource("min/remove-promotions.min.css", 6),
guiSettingsStyle: new Resource("min/gui-settings.min.scss", 0),
fullTweetsTitleStyle: new Resource("min/full-tweets-title.min.css", 7),
imageViewerStyle: new Resource("min/image-viewer.min.scss", 8),
toastStyle: new Resource("min/toast.min.scss", 9),
blurVideoControlStyle: new Resource("min/blur-video-control.min.css", 10),
forceWideStyle: new Resource("min/force-wide.min.scss"),
guiSettingsDom: new Resource("min/gui-settings.min.html"),
imageViewerDom: new Resource("min/image-viewer.min.html"),
latestVersion: new Resource("version.txt"),
guiSettings: new Resource("min/gui-settings.min.js"),
useDarkStyle: new Resource("min/dark-styles.min.js"),
useNewStyle: new Resource("min/new-styles.min.js"),
overrideNavBar: new Resource("min/override-navbar.min.js"),
touchNavBar: new Resource("min/touch-navbar.min.js"),
touchVideoPlayer: new Resource("min/touch-player.min.js"),
expandDanmakuList: new Resource("min/expand-danmaku.min.js"),
removeAds: new Resource("min/remove-promotions.min.js"),
watchLaterRedirect: new Resource("min/watchlater.min.js"),
hideTopSearch: new Resource("min/hide-top-search.min.js"),
harunaScale: new Resource("min/haruna-scale.min.js"),
removeLiveWatermark: new Resource("min/remove-watermark.min.js"),
fullTweetsTitle: new Resource("min/full-tweets-title.min.js"),
viewCover: new Resource("min/view-cover.min.js"),
notifyNewVersion: new Resource("min/notify-new-version.min.js"),
toast: new Resource("min/toast.min.js"),
removeVideoTopMask: new Resource("min/remove-top-mask.min.js"),
blurVideoControl: new Resource("min/blur-video-control.min.js"),
darkSchedule: new Resource("min/dark-schedule.min.js"),
forceWide: new Resource("min/force-wide.min.js"),
clearCache: new Resource("min/clear-cache.min.js")
const resouceManifest = {
style: {
path: "min/style.min.scss",
order: 1
},
oldStyle: {
path: "min/old.min.scss",
order: 1
},
scrollbarStyle: {
path: "min/scrollbar.min.css",
order: 1
},
darkStyle: {
path: "min/dark.min.scss",
order: 2
},
darkStyleImportant: {
path: "min/dark-important.min.scss"
},
darkStyleNavBar: {
path: "min/dark-navbar.min.scss"
},
touchPlayerStyle: {
path: "min/touch-player.min.scss",
order: 3
},
navbarOverrideStyle: {
path: "min/override-navbar.min.css",
order: 4
},
noBannerStyle: {
path: "min/no-banner.min.css",
order: 5
},
removeAdsStyle: {
path: "min/remove-promotions.min.css",
order: 6
},
guiSettingsStyle: {
path: "min/gui-settings.min.scss",
order: 0
},
fullTweetsTitleStyle: {
path: "min/full-tweets-title.min.css",
order: 7
},
imageViewerStyle: {
path: "min/image-viewer.min.scss",
order: 8
},
toastStyle: {
path: "min/toast.min.scss",
order: 9
},
blurVideoControlStyle: {
path: "min/blur-video-control.min.css",
order: 10
},
forceWideStyle: {
path: "min/force-wide.min.scss"
},
downloadVideoStyle: {
path: "min/download-video.min.scss"
},
guiSettingsDom: {
path: "min/gui-settings.min.html"
},
imageViewerDom: {
path: "min/image-viewer.min.html"
},
downloadVideoDom: {
path: "min/download-video.min.html"
},
latestVersion: {
path: "version.txt"
},
guiSettings: {
path: "min/gui-settings.min.js",
dependencies: [
"guiSettingsDom",
"guiSettingsStyle"
],
displayNames: {
guiSettings: "设置",
blurSettingsPanel: "模糊设置面板背景"
}
},
useDarkStyle: {
path: "min/dark-styles.min.js",
dependencies: [
"darkStyle",
"darkStyleImportant",
"darkStyleNavBar",
"scrollbarStyle"
],
displayNames: {
useDarkStyle: "夜间模式"
}
},
useNewStyle: {
path: "min/new-styles.min.js",
dependencies: [
"style",
"oldStyle",
"scrollbarStyle"
],
displayNames: {
useNewStyle: "样式调整",
blurBackgroundOpacity: "顶栏(对横幅)不透明度"
}
},
overrideNavBar: {
path: "min/override-navbar.min.js",
dependencies: [
"navbarOverrideStyle",
"noBannerStyle"
],
displayNames: {
overrideNavBar: "搜索栏置顶",
showBanner: "显示顶部横幅"
}
},
touchNavBar: {
path: "min/touch-navbar.min.js",
displayNames: {
touchNavBar: "顶栏触摸优化"
}
},
touchVideoPlayer: {
path: "min/touch-player.min.js",
dependencies: [
"touchPlayerStyle"
],
displayNames: {
touchVideoPlayer: "播放器触摸支持",
touchVideoPlayerAnimation: "启用实验性动画效果",
touchVideoPlayerDoubleTapControl: "启用双击控制"
}
},
expandDanmakuList: {
path: "min/expand-danmaku.min.js",
displayNames: {
expandDanmakuList: "自动展开弹幕列表"
}
},
removeAds: {
path: "min/remove-promotions.min.js",
dependencies: [
"removeAdsStyle"
],
displayNames: {
removeAds: "删除广告"
}
},
watchLaterRedirect: {
path: "min/watchlater.min.js",
displayNames: {
watchLaterRedirect: "稍后再看重定向"
}
},
hideTopSearch: {
path: "min/hide-top-search.min.js",
displayNames: {
hideTopSearch: "隐藏搜索推荐"
}
},
harunaScale: {
path: "min/haruna-scale.min.js",
displayNames: {
harunaScale: "缩放看板娘"
}
},
removeLiveWatermark: {
path: "min/remove-watermark.min.js",
displayNames: {
removeLiveWatermark: "删除直播水印"
}
},
fullTweetsTitle: {
path: "min/full-tweets-title.min.js",
dependencies: [
"fullTweetsTitleStyle"
],
displayNames: {
fullTweetsTitle: "展开动态标题"
}
},
viewCover: {
path: "min/view-cover.min.js",
dependencies: [
"imageViewerDom",
"imageViewerStyle"
],
displayNames: {
viewCover: "查看封面"
}
},
notifyNewVersion: {
path: "min/notify-new-version.min.js",
dependencies: [
"latestVersion"
],
displayNames: {
notifyNewVersion: "检查更新"
}
},
toast: {
path: "min/toast.min.js",
dependencies: [
"toastStyle"
],
displayNames: {
toast: "显示消息"
}
},
removeVideoTopMask: {
path: "min/remove-top-mask.min.js",
displayNames: {
removeVideoTopMask: "删除视频标题层"
}
},
blurVideoControl: {
path: "min/blur-video-control.min.js",
dependencies: [
"blurVideoControlStyle"
],
displayNames: {
blurVideoControl: "模糊视频控制栏背景"
}
},
darkSchedule: {
path: "min/dark-schedule.min.js",
displayNames: {
darkSchedule: "夜间模式计划时段",
darkScheduleStart: "起始时间",
darkScheduleEnd: "结束时间"
}
},
forceWide: {
path: "min/force-wide.min.js",
dependencies: [
"forceWideStyle"
],
displayNames: {
forceWide: "强制宽屏",
forceWideMinWidth: "触发宽度"
}
},
clearCache: {
path: "min/clear-cache.min.js",
displayNames: {
useCache: "启用缓存"
}
},
downloadVideo: {
path: "min/download-video.min.js",
dependencies: [
"downloadVideoDom",
"downloadVideoStyle",
"videoInfo"
]
},
videoInfo: {
path: "min/video-info.min.js"
},
aboutDom: {
path: "min/about.min.html"
},
aboutStyle: {
path: "min/about.min.scss"
},
about: {
path: "min/about.min.js",
dependencies: [
"aboutDom",
"aboutStyle"
]
}
};
(function ()
Resource.root = "https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/";
Resource.all = {};
Resource.displayNames = {};
for (const [key, data] of Object.entries(resouceManifest))
{
this.guiSettings.dependencies = [
this.guiSettingsDom,
this.guiSettingsStyle
];
this.useDarkStyle.dependencies = [
this.darkStyle,
this.darkStyleImportant,
this.darkStyleNavBar,
this.scrollbarStyle
];
this.useNewStyle.dependencies = [
this.style,
this.oldStyle,
this.scrollbarStyle
];
this.overrideNavBar.dependencies = [
this.navbarOverrideStyle,
this.noBannerStyle
];
this.touchVideoPlayer.dependencies = [
this.touchPlayerStyle
];
this.removeAds.dependencies = [
this.removeAdsStyle
];
this.fullTweetsTitle.dependencies = [
this.fullTweetsTitleStyle
];
this.viewCover.dependencies = [
this.imageViewerDom,
this.imageViewerStyle
];
this.notifyNewVersion.dependencies = [
this.latestVersion
];
this.toast.dependencies = [
this.toastStyle
];
this.blurVideoControl.dependencies = [
this.blurVideoControlStyle
];
this.forceWide.dependencies = [
this.forceWideStyle
];
}).apply(Resource.all);
(function ()
const resource = new Resource(data.path, data.order);
resource.key = key;
if (data.displayNames)
{
resource.displayName = data.displayNames[key];
Object.assign(Resource.displayNames, data.displayNames);
}
Resource.all[key] = resource;
}
for (const [key, data] of Object.entries(resouceManifest))
{
this.guiSettings.displayName = "设置";
this.useDarkStyle.displayName = "夜间模式";
this.useNewStyle.displayName = "样式调整";
this.overrideNavBar.displayName = "搜索栏置顶";
this.touchNavBar.displayName = "顶栏触摸优化";
this.touchVideoPlayer.displayName = "播放器触摸支持";
this.expandDanmakuList.displayName = "自动展开弹幕列表";
this.removeAds.displayName = "删除广告";
this.watchLaterRedirect.displayName = "稍后再看重定向";
this.hideTopSearch.displayName = "隐藏搜索推荐";
this.harunaScale.displayName = "缩放看板娘";
this.removeLiveWatermark.displayName = "删除直播水印";
this.fullTweetsTitle.displayName = "展开动态标题";
this.viewCover.displayName = "查看封面";
this.notifyNewVersion.displayName = "新版本提醒";
this.toast.displayName = "显示消息";
this.removeVideoTopMask.displayName = "删除视频标题层";
this.blurVideoControl.displayName = "模糊视频控制栏背景";
this.darkSchedule.displayName = "夜间模式计划时段";
this.forceWide.displayName = "强制宽屏";
}).apply(Resource.all);
if (data.dependencies)
{
Resource.all[key].dependencies = data.dependencies.map(name => Resource.all[name]);
}
}
}
function downloadText(url, load, error)
{
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () => load && load(xhr.responseText));
xhr.addEventListener("error", () => error && error(xhr.responseText));
xhr.open("GET", url);
xhr.send();
if (load) // callback
{
xhr.addEventListener("load", () => load && load(xhr.responseText));
xhr.addEventListener("error", () => error && error(xhr.responseText));
xhr.send();
}
else
{
return new Promise((resolve, reject) =>
{
xhr.addEventListener("load", () => resolve(xhr.responseText));
xhr.addEventListener("error", () => reject(xhr.responseText));
xhr.send();
});
}
}
function fixed(number, precision = 1)
{
const str = number.toString();
const index = str.indexOf(".");
if (index !== -1)
{
if (str.length - index > precision + 1)
{
return str.substring(0, index + precision + 1);
}
else
{
return str;
}
}
else
{
return str + ".0";
}
}
// Placeholder class for Toast
class Toast
@ -561,17 +787,19 @@
{
return new ResourceType("html", html =>
{
const keys = Object.keys(Resource.all).filter(key => Resource.all[key].displayName);
for (const key of keys)
for (const [key, name] of Object.entries(Resource.displayNames))
{
html = html
.replace(new RegExp(`(<checkbox\\s*?indent=".+?"\\s*?key="${key}"\\s*?dependencies=".*?">)[^\\0]*?(</checkbox>)`, "g"),
`$1${Resource.all[key].displayName}$2`);
html = html.replace(new RegExp(`(<(.+)\\s*?indent="[\\d]+?"\\s*?key="${key}"\\s*?dependencies=".*?">)[^\\0]*?(</\\2>)`, "g"),
`$1${name}$3`);
}
return html
.replace(/<category>([^\0]*?)<\/category>/g, `
return html.replace(/<category>([^\0]*?)<\/category>/g, `
<li class="indent-center category">
<span class="settings-category">$1</span>
<span class="settings-category">
$1
<i class="settings-category-arrow"></i>
</span>
</li>
<li class="indent-center widgets-container" category-name="$1">
</li>
`).replace(/<checkbox\s*?indent="(.+?)"\s*?key="(.+?)"\s*?dependencies="(.*?)">([^\0]*?)<\/checkbox>/g, `
<li class="indent-$1">
@ -612,16 +840,13 @@
{
return this.text !== null;
}
get key()
{
return Object.keys(Resource.all).find(k => Resource.all[k] === this);
}
constructor(url, priority)
{
this.url = Resource.root + url;
this.dependencies = [];
this.priority = priority;
this.text = null;
this.key = null;
this.type = ResourceType.fromUrl(url);
this.displayName = "";
}
@ -779,6 +1004,9 @@
return null;
}
const promise = resource.download();
resource.dependencies
.filter(it => it.type.name === "script")
.forEach(it => this.fetchByKey(it.key));
return new Promise(resolve =>
{
promise.then(text =>
@ -854,6 +1082,10 @@
{
panel.find(info.before()).before(info.content);
}
else if (info.category)
{
panel.find(`.widgets-container[category-name=${info.category}]`).append(info.content);
}
if (info.success)
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
images/download-video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
images/force-wide-after.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

1
min/about.min.html Normal file
View File

@ -0,0 +1 @@
<div class="bilibili-evolved-about"></div>

1
min/about.min.js vendored Normal file
View File

@ -0,0 +1 @@
(()=>{return(t,n)=>{$("body").append(n.data.aboutDom.text);function e(){n.applyStyle("aboutStyle");$("#about-link").on("click",()=>{$(".bilibili-evolved-about").toggleClass("opened")})}return{settingsWidget:{after:()=>$(".gui-settings-content"),content:`\n <div class="about gui-settings-footer">\n <span id="about-version">${GM_info.script.name}, version ${t.currentVersion}</span>\n <span id="about-link">About</span>\n </div>`,success:e}}}})();

1
min/about.min.scss Normal file
View File

@ -0,0 +1 @@
.about.gui-settings-footer{height:24px;font-size:14px;justify-content:space-between;padding:6px 24px;border-top:1px dashed #8884;}.about.gui-settings-footer>span{opacity:0.2;}.bilibili-evolved-about{display:none;width:60vw;height:40vh;background-color:white;position:absolute;top:20%;left:20%;z-index:100000;box-shadow:0px 3px 20px 2px #0004;}.bilibili-evolved-about.opened{display:flex;}#about-link{cursor:pointer;transition:all .2s;}#about-link:hover{opacity:1;color:$customStyleColor;}

View File

@ -1 +1 @@
(()=>{return(e,n)=>{return{settingsWidget:{after:()=>$("input[key=useCache]").parent().parent(),content:`<li class="indent-center">\n <button\n class="gui-settings-button"\n title="清除缓存"\n id="clear-cache">\n 清除缓存\n </button>\n </li>`,success:()=>{$("#clear-cache").on("click",()=>{e.cache={};Toast.show("已删除全部缓存.","清除缓存",5e3)});if(typeof offlineData!=="undefined"){$("button#clear-cache").parent().addClass("hidden")}}}}}})();
(()=>{return(t,e)=>{return{settingsWidget:{category:"其他",content:`<div>\n <button\n class="gui-settings-button"\n title="清除缓存"\n id="clear-cache">\n 清除缓存\n </button>\n </div>`,success:()=>{$("#clear-cache").on("click",()=>{t.cache={};Toast.show("已删除全部缓存.","清除缓存",5e3)});if(typeof offlineData!=="undefined"){$("button#clear-cache").parent().addClass("hidden")}}}}}})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<div style="position: relative;" class="hidden"><button class="gui-settings-button" title="下载当前视频" id="download-video">下载视频</button><div class="download-video-panel quality"><ol class="video-quality"></ol><div class="video-action"><div id="video-action-download">直接下载</div><div id="video-action-copy">复制链接</div></div><div class="video-progress"><div class="download-progress-text"><span class="download-progress-title">正在下载</span><span class="download-progress-value">0</span><span class="download-progress-percent">%</span></div><div class="download-progress-background"><div class="download-progress-foreground"></div></div><div class="download-progress-cancel"><span>取消</span></div></div><div class="video-error"></div><a href="" id="video-complete"></a></div></div>

1
min/download-video.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.download-video-panel.opened{transform:scaleY(1);}.download-video-panel{position:absolute;top:calc(100% + 8px);transition:all .16s ease-out;transform-origin:top;transform:scaleY(0);background:white;border-radius:4px;box-shadow:0px 3px 20px 2px #0004;z-index:100;}.gui-settings-content ol.video-quality li,.video-action>div{cursor:pointer;align-items:center;margin:0;padding:8px 16px;border-radius:4px;transition:all .2s ease-out;}.video-action>div{padding:12px 24px;}.gui-settings-content ol.video-quality li:hover,.video-action>div:hover{background:rgba(0,0,0,0.16);}.video-quality,.video-progress,.video-action,.video-error{display:none;}.download-video-panel.quality:not(.error) .video-quality,.download-video-panel.progress:not(.error) .video-progress,.download-video-panel.action:not(.error) .video-action,.download-video-panel.error .video-error{display:block;}.download-progress-text{display:flex;}.download-progress-title{flex:1 0 0;}.download-progress-background{background-color:#8884;height:4px;width:100%;margin-top:4px;}.download-progress-foreground{background-color:$customStyleColor;transform-origin:left;transition:all .2s ease-out;transform:scaleX(0);height:100%;width:100%;}.download-progress-cancel{margin-top:8px;display:flex;justify-content:center;}.download-progress-cancel>span{border-radius:4px;background-color:#8884;padding:4px 8px;cursor:pointer;}.download-progress-cancel>span:hover{opacity:.9;}.download-progress-cancel>span:active{opacity:.8;}.video-error,.video-progress{padding:12px;}.video-progress{min-width:160px;}#video-complete{display:none;}

View File

@ -1 +1 @@
<div class="gui-settings-panel"><div class="gui-settings-box"><div class="gui-settings-header"><span class="gui-settings-title">设置</span><svg class="gui-settings-close" viewBox="0 0 24 24"><path/></svg></div><div class="gui-settings-content"><ul><category>样式</category><li class="indent-0"><label class="gui-settings-textbox-container"><span>主题颜色</span><div class="custom-color-preview"><div class="predefined-colors"><div class="predefined-colors-grid"></div></div></div><input key="customStyleColor" dependencies="" spellcheck="false" type="text"/></label></li><checkbox indent="0" key="useNewStyle" dependencies=""></checkbox><textbox indent="1" key="blurBackgroundOpacity" dependencies="useNewStyle">顶栏(对横幅)不透明度</textbox><checkbox indent="0" key="useDarkStyle" dependencies=""></checkbox><checkbox indent="0" key="darkSchedule" dependencies=""></checkbox><textbox indent="1" key="darkScheduleStart" dependencies="darkSchedule">起始时间</textbox><textbox indent="1" key="darkScheduleEnd" dependencies="darkSchedule">结束时间</textbox><checkbox indent="0" key="overrideNavBar" dependencies=""></checkbox><checkbox indent="1" key="showBanner" dependencies="overrideNavBar">显示顶部横幅</checkbox><checkbox indent="0" key="forceWide" dependencies=""></checkbox><textbox indent="1" key="forceWideMinWidth" dependencies="forceWide">触发宽度</textbox><category>工具</category><checkbox indent="0" key="removeAds" dependencies=""></checkbox><checkbox indent="0" key="watchLaterRedirect" dependencies=""></checkbox><checkbox indent="0" key="hideTopSearch" dependencies=""></checkbox><checkbox indent="0" key="fullTweetsTitle" dependencies=""></checkbox><category>视频与直播</category><checkbox indent="0" key="expandDanmakuList" dependencies=""></checkbox><checkbox indent="0" key="harunaScale" dependencies=""></checkbox><checkbox indent="0" key="removeLiveWatermark" dependencies=""></checkbox><checkbox indent="0" key="removeVideoTopMask" dependencies=""></checkbox><checkbox indent="0" key="blurVideoControl" dependencies=""></checkbox><category>触摸优化</category><checkbox indent="0" key="touchNavBar" dependencies=""></checkbox><checkbox indent="0" key="touchVideoPlayer" dependencies=""></checkbox><checkbox indent="1" key="touchVideoPlayerAnimation" dependencies="touchVideoPlayer">启用实验性动画效果</checkbox><checkbox indent="1" key="touchVideoPlayerDoubleTapControl" dependencies="touchVideoPlayer">启用双击控制</checkbox><category>其他</category><checkbox indent="0" key="toast" dependencies=""></checkbox><checkbox indent="0" key="blurSettingsPanel" dependencies="">模糊设置面板背景</checkbox><checkbox indent="0" key="useCache" dependencies="">启用缓存</checkbox></ul></div></div></div>
<div class="gui-settings-panel"><div class="gui-settings-box"><div class="gui-settings-header"><span class="gui-settings-title">设置</span><svg class="gui-settings-close" viewBox="0 0 24 24"><path/></svg></div><div class="gui-settings-content"><ul><category>样式</category><li class="indent-0"><label class="gui-settings-textbox-container"><span>主题颜色</span><div class="custom-color-preview"><div class="predefined-colors"><div class="predefined-colors-grid"></div></div></div><input key="customStyleColor" dependencies="" spellcheck="false" type="text"/></label></li><checkbox indent="0" key="useNewStyle" dependencies=""></checkbox><textbox indent="1" key="blurBackgroundOpacity" dependencies="useNewStyle"></textbox><checkbox indent="0" key="useDarkStyle" dependencies=""></checkbox><checkbox indent="0" key="darkSchedule" dependencies=""></checkbox><textbox indent="1" key="darkScheduleStart" dependencies="darkSchedule"></textbox><textbox indent="1" key="darkScheduleEnd" dependencies="darkSchedule"></textbox><checkbox indent="0" key="overrideNavBar" dependencies=""></checkbox><checkbox indent="1" key="showBanner" dependencies="overrideNavBar"></checkbox><checkbox indent="0" key="forceWide" dependencies=""></checkbox><textbox indent="1" key="forceWideMinWidth" dependencies="forceWide"></textbox><category>工具</category><checkbox indent="0" key="removeAds" dependencies=""></checkbox><checkbox indent="0" key="watchLaterRedirect" dependencies=""></checkbox><checkbox indent="0" key="hideTopSearch" dependencies=""></checkbox><checkbox indent="0" key="fullTweetsTitle" dependencies=""></checkbox><category>视频与直播</category><checkbox indent="0" key="expandDanmakuList" dependencies=""></checkbox><checkbox indent="0" key="harunaScale" dependencies=""></checkbox><checkbox indent="0" key="removeLiveWatermark" dependencies=""></checkbox><checkbox indent="0" key="removeVideoTopMask" dependencies=""></checkbox><checkbox indent="0" key="blurVideoControl" dependencies=""></checkbox><category>触摸优化</category><checkbox indent="0" key="touchNavBar" dependencies=""></checkbox><checkbox indent="0" key="touchVideoPlayer" dependencies=""></checkbox><checkbox indent="1" key="touchVideoPlayerAnimation" dependencies="touchVideoPlayer"></checkbox><checkbox indent="1" key="touchVideoPlayerDoubleTapControl" dependencies="touchVideoPlayer"></checkbox><category>其他</category><checkbox indent="0" key="toast" dependencies=""></checkbox><checkbox indent="0" key="blurSettingsPanel" dependencies=""></checkbox><checkbox indent="0" key="useCache" dependencies=""></checkbox></ul></div></div></div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
min/video-info.min.js vendored Normal file
View File

@ -0,0 +1 @@
(()=>{return()=>{class i{constructor(i){this.aid=i}async fetchInfo(){const i=JSON.parse(await downloadText(`https://api.bilibili.com/x/web-interface/view?aid=${this.aid}`));if(i.code!==0){throw new Error(i.message)}const t=i.data;this.cid=t.cid;this.pageCount=t.videos;this.coverUrl=t.pic;this.tagId=t.tid;this.tagName=t.tname;this.title=t.title;this.description=t.desc;this.up={uid:t.owner.mid,name:t.owner.name,faceUrl:t.owner.face};this.pages=t.pages.map(i=>{return{cid:i.cid,title:i.part,pageNumber:i.page}});return this}}class t{constructor(i){this.ep=i;this.videos=[]}async fetchInfo(){const t=await downloadText(`https://www.bilibili.com/bangumi/play/ep${this.ep}/`);const e=JSON.parse(t.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){/)[1]);this.title=e.mediaInfo.title;this.cover=e.mediaInfo.cover;this.squareCover=e.mediaInfo.square_cover;this.aid=e.epInfo.aid;this.cid=e.epInfo.cid;this.videos=e.epList.map(async t=>{return{title:t.index_title,aid:t.aid,cid:t.cid,info:await new i(t.aid).fetchInfo()}});return this}}return{export:{VideoInfo:i,BangumiInfo:t}}}})();

View File

@ -1 +1 @@
(()=>{return(e,t)=>{class n{constructor(e){this.url=e;if($(".image-viewer").length===0){this.createDom()}this.viewer=$(".image-viewer-container");this.downloadImage()}createDom(){$("body").append(t.data.imageViewerDom.text);t.applyStyle("imageViewerStyle");$(".image-viewer-container .close").on("click",()=>this.hide())}downloadImage(){const e=new XMLHttpRequest;e.open("GET",this.url.replace("http:","https:"),true);e.responseType="blob";e.onload=(()=>{const t=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","");const n=URL.createObjectURL(e.response);this.imageData=n;this.viewer.find(".download").attr("href",n).attr("download",t);this.viewer.find(".image").prop("src",n)});e.send()}show(){this.viewer.addClass("opened");$("html,body").addClass("image-viewer-opened")}hide(){this.viewer.removeClass("opened");$("html,body").removeClass("image-viewer-opened")}}if($("meta[itemprop='image']").length>0){return{settingsWidget:{after:()=>$("span.settings-category").filter((e,t)=>t.innerHTML==="视频与直播").parent(),content:`<li class="indent-center hidden">\n <button\n class="gui-settings-button"\n title="查看当前视频的封面"\n id="view-video-cover">\n 查看封面\n </button>\n </li>`,success:()=>{new SpinQuery(()=>$("meta[itemprop='image']"),e=>e.length>0&&e.prop("content"),e=>{const t=new n(e.prop("content"));$("#view-video-cover").on("click",()=>{t.show()}).parent().removeClass("hidden")}).start()}}}}else{return{settingsWidget:{after:()=>$("span.settings-category").filter((e,t)=>t.innerHTML==="视频与直播").parent(),content:`<li class="indent-center hidden">\n <button\n class="gui-settings-button"\n title="查看当前直播的封面"\n id="view-live-cover">\n 查看封面\n </button>\n </li>`,success:()=>{SpinQuery.any(()=>$(".header-info-ctnr .room-cover"),e=>{const t=e.attr("href").match(/space\.bilibili\.com\/([\d]+)/);if(t&&t[1]){const e=t[1];const i=`https://api.live.bilibili.com/bili/getRoomInfo/${e}`;downloadText(i,e=>{const t=e.slice(1,-2);const i=JSON.parse(t).data.cover;const o=new n(i);$("#view-live-cover").on("click",()=>{o.show()}).parent().removeClass("hidden")})}})}}}}}})();
(()=>{return(e,t)=>{class i{constructor(e){this.url=e;if($(".image-viewer").length===0){this.createDom()}this.viewer=$(".image-viewer-container");this.downloadImage()}createDom(){$("body").append(t.data.imageViewerDom.text);t.applyStyle("imageViewerStyle");$(".image-viewer-container .close").on("click",()=>this.hide())}downloadImage(){const e=new XMLHttpRequest;e.open("GET",this.url.replace("http:","https:"),true);e.responseType="blob";e.onload=(()=>{const t=document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili","");const i=URL.createObjectURL(e.response);this.imageData=i;this.viewer.find(".download").attr("href",i).attr("download",t);this.viewer.find(".image").prop("src",i)});e.send()}show(){this.viewer.addClass("opened")}hide(){this.viewer.removeClass("opened")}}if($("meta[itemprop='image'],meta[property='og:image']").length>0){return{settingsWidget:{category:"视频与直播",content:`<div class="hidden">\n <button\n class="gui-settings-button"\n title="查看当前视频的封面"\n id="view-video-cover">\n 查看封面\n </button>\n </div>`,success:()=>{new SpinQuery(()=>$("meta[itemprop='image'],meta[property='og:image']"),e=>e.length>0&&e.prop("content"),e=>{const t=new i(e.prop("content"));$("#view-video-cover").on("click",()=>{t.show()}).parent().removeClass("hidden")}).start()}}}}else{return{settingsWidget:{category:"视频与直播",content:`<div class="hidden">\n <button\n class="gui-settings-button"\n title="查看当前直播的封面"\n id="view-live-cover">\n 查看封面\n </button>\n </div>`,success:()=>{SpinQuery.any(()=>$(".header-info-ctnr .room-cover"),e=>{const t=e.attr("href").match(/space\.bilibili\.com\/([\d]+)/);if(t&&t[1]){const e=t[1];const n=`https://api.live.bilibili.com/bili/getRoomInfo/${e}`;downloadText(n,e=>{const t=e.slice(1,-2);const n=JSON.parse(t).data.cover;const o=new i(n);$("#view-live-cover").on("click",()=>{o.show()}).parent().removeClass("hidden")})}})}}}}}})();

View File

@ -476,7 +476,6 @@ a.bp_box_bot_click,
.medal .medal-form .page-tip,
.empty-wrp .text,
.ui-serch .run-serch,
.container .iconfont,
.container .song-list .song-li .content .num,
.container .host-list-layout .hot-list-wrap .show-more-song,
.container .host-list-layout .hot-list-wrap .hot-song-list .song-info .song-num,

View File

@ -50,7 +50,11 @@ div#square.container,
.live-status.offline,
.banner-wrapper .swiper-pagination-bullet,
.nav-header-wrapper .nav-header .nav-header-search-bar-wrapper .suggestion-list,
.project-list .project-list-item .project-list-item-img
.project-list .project-list-item .project-list-item-img,
.download-video-panel,
.article-action .ops .share-container .weixin-holder,
.coin-wrap,
.bilibili-evolved-about
{
background-color: #222 !important;
}
@ -164,14 +168,17 @@ body>div.to-top.on,
.area-section .card-ctnr .more:hover,
.link-panigation-ctnr .pagination,
.link-progress-tv,
.jumping-ctnr .jumping-input
.jumping-ctnr .jumping-input,
#song_detail_click_upper~div .pager .pages .page-item.active button,
#song_detail_click_upper~div .pager .pages .page-item button,
.filter-wrap .sub-filter
{
background-color: transparent !important;
}
// a
// {
// background: #fff1 !important;
// }
.coin-wrap .coin-nav .coin-checkbox
{
background: #fff !important;
}
// a
// {
// background: transparent !important;
@ -224,7 +231,12 @@ body>div.to-top.on,
.leaveMsg .leaveMsgBody .infoArea .infoAreaTitle,
.leaveMsgUpload .btnarea span.btareatxt,
.evaluate .h2,
.hot-list .card-ctnr .room-count .icon-font
.hot-list .card-ctnr .room-count .icon-font,
.article-action .ops i,
.page-container .article-action,
.article-action .ops .share-container .weixin-holder p,
.coin-wrap .coin-tips,
.up-feedback .up-fb-btn
{
color: #aaa !important;
}
@ -301,7 +313,11 @@ body>div.to-top.on,
.jumping-ctnr .jumping-input,
.banner-wrapper .swiper-pagination-bullet,
.nav-header-wrapper .nav-header .user-panel,
.nav-header-wrapper .nav-header .user-panel a
.nav-header-wrapper .nav-header .user-panel a,
.similar-song-menu .similar-right .title,
.gridview-sidebar .album-title,
.article-holder .bangumi-card a .container .title,
.coin-wrap .coin-title
{
color: #eee !important;
}
@ -346,7 +362,13 @@ body>div.to-top.on,
.evaluateWether .noactive,
.evaluate .situation span,
.bilibili-live-player .bilibili-live-player-enter-tips,
.nav-header-wrapper .nav-header .nav-header-search-bar-wrapper .suggestion-list
.nav-header-wrapper .nav-header .nav-header-search-bar-wrapper .suggestion-list,
.publish-panel .hash-popup,
.hash-popup .topic-container .item.is-selected,
.article-holder .bangumi-card a .container,
.article-action .ops .share-container .weixin-holder,
.coin-wrap .coin-sure,
.filter-wrap .sub-filter
{
border-color: transparent !important;
}
@ -467,6 +489,10 @@ body>div.to-top.on,
{
filter: brightness(0.2) !important;
}
.up-feedback .icon-beta
{
filter: brightness(0.5) !important;
}
// a
// {
// filter: none !important;
@ -510,7 +536,9 @@ body>div.to-top.on,
.mainBox .leaveMsg,
.js-evaluateArea .evaluateDialog,
.project-list .project-list-item:hover,
#app .toolbar-wrapper
.publish-panel .hash-popup,
#app .toolbar-wrapper,
.article-action .ops .share-container .weixin-holder
{
box-shadow: 0px 1px 10px 0px $customStyleColor30 !important;
}
@ -521,7 +549,8 @@ body>div.to-top.on,
.nav-bar .sub-nav::after,
.bui-sns-info a .bd::after,
.more .help .icon,
.more .link .icon
.more .link .icon,
.filter-wrap .icon-tid2-arr
{
display: none !important;
}
@ -562,6 +591,10 @@ body>div.to-top.on
{
background-repeat: no-repeat !important;
}
.article-action .ops .share-container .weixin-holder p
{
margin-bottom: 10px !important;
}
.list-filter-bar .sort-box .item.active,
.list-filter-bar .sort-box .item:hover,
@ -635,7 +668,9 @@ body>div.to-top.on
.bilibili-live-player .blpui-btn.default-btn.btn-blue,
.bilibili-live-player .bilibili-live-player-enter-tips,
.banner-wrapper .swiper-pagination-bullet-active,
.nav-header-wrapper .nav-header .profile-img.active::before
.nav-header-wrapper .nav-header .profile-img.active::before,
.coin-wrap .coin-sure,
.up-feedback .up-fb-btn:hover
{
background-color: $customStyleColor !important;
}
@ -708,7 +743,25 @@ body>div.to-top.on
.hot-list .card-ctnr .room-count:hover .amount,
.hot-list .card-ctnr .room-count:hover .icon-font,
.hot-list .card-ctnr .room-count:hover,
.panel-list .order-center-item:hover a
.panel-list .order-center-item:hover a,
.similar-song-menu .similar-right .title:hover,
#song_detail_click_upper~div .pager .pages .page-item.active button,
#song_detail_click_upper~div .pager .pages .page-item button:hover,
.article-action .coin-btn.on,
.article-action .coin-btn.on i,
.article-action .coin-btn:hover,
.article-action .coin-btn:hover i,
.article-action .fav-btn.on,
.article-action .fav-btn.on i,
.article-action .fav-btn:hover,
.article-action .fav-btn:hover i,
.article-action .like-btn.on,
.article-action .like-btn.on i,
.article-action .like-btn:hover,
.article-action .like-btn:hover i,
.article-action .ops i:hover,
.coin-wrap .coin-title i,
.coin-wrap .coin-nav .coin-checkbox.on .lable
{
color: $customStyleColor !important;
}
@ -739,7 +792,9 @@ body>div.to-top.on
.evaluateSubmitArea .submit,
.bilibili-live-player .blpui-btn.default-btn.btn-blue,
.bilibili-live-player .bilibili-live-player-enter-tips,
.banner-wrapper .swiper-pagination-bullet-active
.banner-wrapper .swiper-pagination-bullet-active,
.coin-wrap .coin-sure,
.up-feedback .up-fb-btn:hover
{
color: $foreground !important;
}

View File

@ -2,7 +2,18 @@
.title-factory-card,
.p-relative.gold-seed-store.over-hidden .content,
.live-btn.default,
.collapse-subitem--active
.collapse-subitem--active,
.invtable tr:nth-child(odd) td,
.el-input-group__append,
.el-input-group__prepend,
.cc-article-wrp .article-card .meta-view .appeal,
.cc-article-wrp .article-card .meta-view .data,
.cc-article-wrp .article-card .meta-view .delete,
.cc-article-wrp .article-card .meta-view .option,
.comment-list-item .ci-action a:hover,
.comment-manage-wrap .content .action-bar .dropdown .action-menu li:hover,
.comment-manage-wrap .content .action-bar .dropdown .sort-menu li:hover,
.hash-popup .topic-container .item.is-selected
{
background-color: #222 !important;
}
@ -10,7 +21,20 @@
.title-item,
.help-list,
.help-box,
.right-action-ctnr.pointer.dp-i-block.primary.btn.p-relative .btn.primary
.right-action-ctnr.pointer.dp-i-block.primary.btn.p-relative .btn.primary,
.code-content,
.invtable .codedone,
.cc-article-wrp .article-card,
.videoCharts .stat .stat-wrp,
.article-data-wrp .video-box,
.article-net-charts .content-box,
.article-net-charts .area,
.comment-manage-wrap .content,
.head .dropdown-btn,
.head .dropdown.open .dropdown-btn,
.dc-button.dc-button-text,
.dc-progress-bar,
.h-none-btn
{
background-color: #444 !important;
}
@ -26,7 +50,8 @@
// {
// background-color: #fff1 !important;
// }
.live-haruna .section-stage .stage-wrap
.live-haruna .section-stage .stage-wrap,
.tabs-nav .active
{
background-image: none !important;
}
@ -59,7 +84,16 @@
.record-ctnr .summary .s-item .title,
.main_body .future .future_list .future_block .info .loca,
.edit-button > span,
.room-introduction-content.empty
.room-introduction-content.empty,
.invitation-subtitle,
.cc-article-wrp .article-card .meta-title .typename,
.cc-article-wrp .article-card .meta-view .appeal,
.cc-article-wrp .article-card .meta-view .data,
.cc-article-wrp .article-card .meta-view .delete,
.cc-article-wrp .article-card .meta-view .option,
.article-data-wrp .menu-wrp .menu-tips,
.type-rank-item-label,
.h-none-msg
{
color: #aaa !important;
}
@ -78,7 +112,23 @@
.collapse-item a,
.help-subtitle,
.collapse-subitem--active a,
.drop-menu-item
.drop-menu-item,
.invitation-title,
.code-btn,
table.invtable td,
.invtable .codedone,
.el-input-group__append,
.el-input-group__prepend,
.cc-article-wrp .article-header .search-wrp input,
.head .dropdown-menu .search .bili-input,
#dc-section_summary .source-rank-list-item .video-info-title a,
.dc-button.dc-button-text,
.dc-button.dc-button-text a,
.dc-button.dc-button-text:hover,
.home-top-msg-name,
.h-none-btn,
.h-none-btn:hover,
.big-user-name
{
color: #eee !important;
}
@ -103,12 +153,23 @@
.areas .area,
.record-ctnr .summary,
.help-list,
.help-box
.help-box,
.code-result,
.el-input-group__append,
.el-input-group__prepend,
.page-wrp.is-article.cc-article-wrp .article-card,
.videoCharts .stat .stat-wrp .stat-card,
.article-chart-wrp,
.comment-list-item,
.head .dropdown-btn,
.dropdown .dropdown-menu,
#dc-section_summary .source-rank-list-item
{
border-color: transparent !important;
}
.link-input,
.add-cover
.add-cover,
.cc-article-wrp .article-card .meta-title .typename
{
border-color: #aaa !important;
}
@ -162,10 +223,13 @@
// {
// border-radius: 4px !important;
// }
// a
// {
// box-shadow: none !important;
// }
.videoCharts .stat .stat-wrp,
.article-data-wrp .video-box,
.article-net-charts .content-box,
.el-radio-button__orig-radio:checked + .el-radio-button__inner
{
box-shadow: none !important;
}
// a
// {
// box-shadow: 0px 1px 10px 0px $customStyleColor30 !important;
@ -187,9 +251,12 @@
// opacity: 1 !important;
// }
.add-cover:hover,
.category:hover,
.category:not(.gui-settings-content .category):hover,
.data-card .data-box .tab .fan-tab.current:after,
.data-card .fans-box .tab .fan-tab.current:after
.data-card .fans-box .tab .fan-tab.current:after,
.data-card .data-box .tab .fan-tab.current:after,
.data-card .fans-box .tab .fan-tab.current:after,
.section-item .diff-wrp .diff-text:before
{
border-color: $customStyleColor !important;
}
@ -199,7 +266,16 @@
.live-btn.default:active,
.live-btn.default:hover,
.popup-close-btn,
.helper-icon-dots
.helper-icon-dots,
.code-btn,
.code-btn:hover,
.cc-article-wrp .article-card .meta-view .appeal:hover,
.cc-article-wrp .article-card .meta-view .data:hover,
.cc-article-wrp .article-card .meta-view .delete:hover,
.cc-article-wrp .article-card .meta-view .option:hover,
.head .dropdown-btn:hover,
.dc-button.dc-button-text:hover,
.h-none-btn:hover
{
background-color: $customStyleColor !important;
}
@ -209,12 +285,15 @@
.bili-blue,
.text-blue,
.save-btn.active,
.category:hover,
.category:not(.gui-settings-content .category):hover,
.help-title,
.collapse-item--active .collapse-title,
.help-subindex,
.drop-menu-item:hover,
icon-label.hover-text-blue:hover .label
icon-label.hover-text-blue:hover .label,
.stat-card .num .text,
.comment-card .comment-item .comment-info .reply-block .comment-vedio a,
.section-item .diff-wrp .diff-text
{
color: $customStyleColor !important;
}
@ -238,7 +317,10 @@ icon-label.hover-text-blue:hover .label
// border-right-color: transparent !important;
// }
.data-card .data-box .tab .fan-tab.current:after,
.data-card .fans-box .tab .fan-tab.current:after
.data-card .fans-box .tab .fan-tab.current:after,
.data-card .data-box .tab .fan-tab.current:after,
.data-card .fans-box .tab .fan-tab.current:after,
.section-item .diff-wrp .diff-text:before
{
border-left-color: transparent !important;
border-right-color: transparent !important;

View File

@ -14,26 +14,6 @@
}
return { x: x, y: y };
};
const fixed = (number, precision = 1) =>
{
const str = number.toString();
const index = str.indexOf(".");
if (index !== -1)
{
if (str.length - index > precision + 1)
{
return str.substring(0, index + precision + 1);
}
else
{
return str;
}
}
else
{
return str + ".0";
}
};
const secondsToTime = sec =>
{
sec = Math.abs(sec);
@ -303,45 +283,24 @@
{
constructor()
{
const url = window.location.href;
const aidMatch = url.match(/av([\d]+)/);
this.aid = aidMatch[1];
const pageMatch = url.match(/p=([\d]+)/);
this.page = pageMatch ? pageMatch[1] : 1;
this.pagesData = null;
this.cidMap = {};
this.cidData = {};
this.aid = unsafeWindow.aid;
this.cid = unsafeWindow.cid;
this.cidData = null;
this.supportWebp = VideoShot.supportWebp;
downloadText(url, html => this.findCid(html));
}
findCid(html)
{
const match = html.match(/"pages":(\[[^\0]*\]),"embedPlayer"/);
if (match)
{
this.pagesData = JSON.parse(match[1]);
this.pagesData.forEach(pageData =>
{
this.cidMap[pageData.page] = pageData.cid;
});
}
}
getVideoshot(currentTime, done)
{
if (!this.cidData[this.page])
if (!this.cidData)
{
downloadText(`https://api.bilibili.com/x/player/videoshot?aid=${this.aid}&cid=${this.cidMap[this.page]}&index=1`, response =>
downloadText(`https://api.bilibili.com/x/player/videoshot?aid=${this.aid}&cid=${this.cid}&index=1`, response =>
{
this.cidData[this.page] = JSON.parse(response).data;
this.cidData = JSON.parse(response).data;
this.getVideoshot(currentTime, done);
});
}
else
{
const data = this.cidData[this.page];
const data = this.cidData;
const indexData = data.index;
let shotIndex = 0;
for (let index = 0; index < indexData.length - 2; index++)

3
utils/about/about.html Normal file
View File

@ -0,0 +1,3 @@
<div class="bilibili-evolved-about">
</div>

26
utils/about/about.js Normal file
View File

@ -0,0 +1,26 @@
(() =>
{
return (settings, resources) =>
{
$("body").append(resources.data.aboutDom.text);
function init()
{
resources.applyStyle("aboutStyle");
$("#about-link").on("click", () =>
{
$(".bilibili-evolved-about").toggleClass("opened");
});
}
return {
settingsWidget: {
after: () => $(".gui-settings-content"),
content: `
<div class="about gui-settings-footer">
<span id="about-version">${GM_info.script.name}, version ${settings.currentVersion}</span>
<span id="about-link">About</span>
</div>`,
success: init
}
};
};
})();

38
utils/about/about.scss Normal file
View File

@ -0,0 +1,38 @@
.about.gui-settings-footer
{
height: 24px;
font-size: 14px;
justify-content: space-between;
padding: 6px 24px;
border-top: 1px dashed #8884;
}
.about.gui-settings-footer>span
{
opacity: 0.2;
}
.bilibili-evolved-about
{
display: none;
width: 60vw;
height: 40vh;
background-color: white;
position: absolute;
top: 20%;
left: 20%;
z-index: 100000;
box-shadow: 0px 3px 20px 2px #0004;
}
.bilibili-evolved-about.opened
{
display: flex;
}
#about-link
{
cursor: pointer;
transition: all .2s;
}
#about-link:hover
{
opacity: 1;
color: $customStyleColor;
}

View File

@ -4,15 +4,15 @@
{
return {
settingsWidget: {
after: () => $("input[key=useCache]").parent().parent(),
content: `<li class="indent-center">
category: "其他",
content: `<div>
<button
class="gui-settings-button"
title="清除缓存"
id="clear-cache">
清除缓存
</button>
</li>`,
</div>`,
success: () =>
{
$("#clear-cache").on("click", () =>

View File

@ -21,25 +21,15 @@
</label>
</li>
<checkbox indent="0" key="useNewStyle" dependencies=""></checkbox>
<textbox indent="1" key="blurBackgroundOpacity" dependencies="useNewStyle">
顶栏(对横幅)不透明度
</textbox>
<textbox indent="1" key="blurBackgroundOpacity" dependencies="useNewStyle"></textbox>
<checkbox indent="0" key="useDarkStyle" dependencies=""></checkbox>
<checkbox indent="0" key="darkSchedule" dependencies=""></checkbox>
<textbox indent="1" key="darkScheduleStart" dependencies="darkSchedule">
起始时间
</textbox>
<textbox indent="1" key="darkScheduleEnd" dependencies="darkSchedule">
结束时间
</textbox>
<textbox indent="1" key="darkScheduleStart" dependencies="darkSchedule"></textbox>
<textbox indent="1" key="darkScheduleEnd" dependencies="darkSchedule"></textbox>
<checkbox indent="0" key="overrideNavBar" dependencies=""></checkbox>
<checkbox indent="1" key="showBanner" dependencies="overrideNavBar">
显示顶部横幅
</checkbox>
<checkbox indent="1" key="showBanner" dependencies="overrideNavBar"></checkbox>
<checkbox indent="0" key="forceWide" dependencies=""></checkbox>
<textbox indent="1" key="forceWideMinWidth" dependencies="forceWide">
触发宽度
</textbox>
<textbox indent="1" key="forceWideMinWidth" dependencies="forceWide"></textbox>
<category>工具</category>
<checkbox indent="0" key="removeAds" dependencies=""></checkbox>
<checkbox indent="0" key="watchLaterRedirect" dependencies=""></checkbox>
@ -54,20 +44,12 @@
<category>触摸优化</category>
<checkbox indent="0" key="touchNavBar" dependencies=""></checkbox>
<checkbox indent="0" key="touchVideoPlayer" dependencies=""></checkbox>
<checkbox indent="1" key="touchVideoPlayerAnimation" dependencies="touchVideoPlayer">
启用实验性动画效果
</checkbox>
<checkbox indent="1" key="touchVideoPlayerDoubleTapControl" dependencies="touchVideoPlayer">
启用双击控制
</checkbox>
<checkbox indent="1" key="touchVideoPlayerAnimation" dependencies="touchVideoPlayer"></checkbox>
<checkbox indent="1" key="touchVideoPlayerDoubleTapControl" dependencies="touchVideoPlayer"></checkbox>
<category>其他</category>
<checkbox indent="0" key="toast" dependencies=""></checkbox>
<checkbox indent="0" key="blurSettingsPanel" dependencies="">
模糊设置面板背景
</checkbox>
<checkbox indent="0" key="useCache" dependencies="">
启用缓存
</checkbox>
<checkbox indent="0" key="blurSettingsPanel" dependencies=""></checkbox>
<checkbox indent="0" key="useCache" dependencies=""></checkbox>
</ul>
</div>
<!-- <div class="gui-settings-footer">

View File

@ -60,6 +60,17 @@
return settings.blurBackgroundOpacity;
}
};
function getCategoriyItems(category)
{
let element = category.nextElementSibling;
const elements = [];
while (element !== null && !element.classList.contains("category"))
{
elements.push(element);
element = element.nextElementSibling;
}
return elements;
}
function darkScheduleValidate(text, defaultValue)
{
const match = text.match(/^([\d]{1,2}):([\d]{1,2})$/);
@ -109,6 +120,16 @@
{
settingsChange(key, undefined, settings[key]);
}
$(".gui-settings-content ul li.category").each((_, e) =>
{
const items = getCategoriyItems(e);
if (items
.filter(it => !it.classList.contains("disabled"))
.every(it => $(it).has("input:checked").length === 0))
{
$(e).click();
}
});
}
function setupEvents()
{
@ -130,6 +151,11 @@
const box = $(".predefined-colors");
box.toggleClass("opened");
});
$(".gui-settings-content ul li.category").on("click", e =>
{
e.currentTarget.classList.toggle("folded");
getCategoriyItems(e.currentTarget).forEach(it => it.classList.toggle("folded"));
});
onSettingsChange(settingsChange);
}
function listenSettingsChange()
@ -185,22 +211,13 @@
{
disable = false;
}
$(`input[key='${key}']`).prop("disabled", disable);
if (disable)
{
$(`input[key='${key}'][type='text']`).parent().addClass("disabled");
}
else
{
$(`input[key='${key}'][type='text']`).parent().removeClass("disabled");
}
const li = $(`li:has(input[key='${key}'])`);
const action = disable ? "addClass" : "removeClass";
li[action]("disabled");
$(`input[key='${key}'][type='text']`).parent()[action]("disabled");
}
}
const box = $(".predefined-colors");
if (box.hasClass("opened"))
{
box.removeClass("opened");
}
$(".download-video-panel,.predefined-colors").removeClass("opened");
};
$(`input[type='checkbox'][key]`)
.on("change", e => checkBoxChange($(e.target)))
@ -240,18 +257,8 @@
});
}
}
addSettingsIcon($("body"));
const settingsBox = resources.data.guiSettingsDom.text;
if (settingsBox)
function applyBlurEffect()
{
$("body").append(settingsBox);
setupEvents();
fillSvgData();
syncGui();
listenDependencies();
addPredefinedColors();
listenSettingsChange();
if (settings.blurSettingsPanel)
{
$(".gui-settings-box").addClass("blur");
@ -260,16 +267,35 @@
{
$(".gui-settings-panel").addClass("animation");
}
}
function checkOfflineData()
{
if (typeof offlineData !== "undefined")
{
$("li:has(input[key=useCache])").addClass("disabled");
$("input[key=useCache]").prop("disabled", true);
}
}
addSettingsIcon($("body"));
const settingsBox = resources.data.guiSettingsDom.text;
if (settingsBox)
{
$("body").append(settingsBox);
setupEvents();
fillSvgData();
checkOfflineData();
syncGui();
listenDependencies();
addPredefinedColors();
listenSettingsChange();
applyBlurEffect();
}
new SpinQuery(
() => $("body"),
it => it.length > 0 && !(unsafeWindow.parent.window === unsafeWindow),
_ => $(".gui-settings-icon-panel").css("display", "none")
).start();
};
})();
})();

View File

@ -102,7 +102,6 @@
overflow: auto;
position: relative;
overscroll-behavior: contain;
padding-bottom: 16px;
}
.gui-settings-content-top-mask,
.gui-settings-content-bottom-mask
@ -131,9 +130,17 @@
.gui-settings-content ul li
{
font-size: 16px;
margin: 12px 0;
margin-bottom: 12px;
display: flex;
height: 24px;
transition: all .2s;
overflow: hidden;
}
.gui-settings-content ul li.disabled,
.gui-settings-content ul li:not(.category).folded
{
height: 0;
margin: 0;
}
.gui-settings-content ul li.indent-0
{
@ -152,20 +159,44 @@
align-items: center;
justify-content: center;
}
.gui-settings-content ul li.widgets-container
{
margin: 0;
height: auto;
width: 100%;
display: flex;
flex-wrap: wrap;
overflow: visible;
}
.gui-settings-content ul li.widgets-container>div
{
align-items: center;
justify-content: center;
min-width: 50%;
display: inline-flex;
margin-bottom: 12px;
}
.gui-settings-content ul li.category
{
padding: 8px 0;
margin: 0;
margin-bottom: 12px;
border-top: 1px dashed #8884;
border-bottom: 1px dashed #8884;
background: white;
position: sticky;
top: 0;
z-index: 10;
cursor: pointer;
transition: all .2s ease-out;
-webkit-tap-highlight-color: transparent;
}
.gui-settings-content ul li.category.folded
{
margin-bottom: -1px;
}
span.settings-category
{
opacity: 0.6;
opacity: 0.8;
}
.gui-settings-title
{
@ -454,3 +485,29 @@ input[type='text'][key]
{
transition: all .2s ease-out;
}
i.settings-category-arrow
{
transform-origin: center;
transition: all .2s ease-out;
transform: translateY(2.828427px) rotate(-135deg);
height: 100%;
display: inline-block;
margin-left: 12px;
}
li.category.folded i.settings-category-arrow
{
transform: translateY(-2.828427px) rotate(45deg);
}
i.settings-category-arrow::after
{
content: "";
width: 8px;
height: 8px;
background-color: transparent;
border: 2px solid white;
opacity: .8;
display: block;
border-left-color: transparent;
border-top-color: transparent;
border-radius: 2.4px;
}

View File

@ -1 +1 @@
1.5.10
1.5.22

View File

@ -0,0 +1,27 @@
<div style="position: relative;" class="hidden">
<button class="gui-settings-button" title="下载当前视频" id="download-video">
下载视频
</button>
<div class="download-video-panel quality">
<ol class="video-quality">
</ol>
<div class="video-action">
<div id="video-action-download">直接下载</div>
<div id="video-action-copy">复制链接</div>
</div>
<div class="video-progress">
<div class="download-progress-text">
<span class="download-progress-title">正在下载</span>
<span class="download-progress-value">0</span>
<span class="download-progress-percent">%</span>
</div>
<div class="download-progress-background">
<div class="download-progress-foreground"></div>
</div>
<div class="download-progress-cancel"><span>取消</span></div>
</div>
<div class="video-error"></div>
<a href="" id="video-complete"></a>
</div>
</div>

View File

@ -0,0 +1,334 @@
(() =>
{
return (_, resources) =>
{
const VideoInfo = resources.attributes.videoInfo.export.VideoInfo;
const BangumiInfo = resources.attributes.videoInfo.export.BangumiInfo;
const pageData = {
aid: undefined,
cid: undefined,
isBangumi: false,
isMovie: false
};
class VideoFormat
{
constructor(quality, internalName, displayName)
{
this.quality = quality;
this.internalName = internalName;
this.displayName = displayName;
}
async downloadInfo()
{
const videoInfo = new VideoDownloadInfo(this);
await videoInfo.fetchVideoInfo();
return videoInfo;
}
static get availableFormats()
{
return new Promise((resolve, reject) =>
{
const url = `https://api.bilibili.com/x/player/playurl?avid=${pageData.aid}&cid=${pageData.cid}&otype=json`;
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () =>
{
const json = JSON.parse(xhr.responseText);
if (json.code !== 0)
{
reject("获取清晰度信息失败.");
}
const data = json.data;
const qualities = data.accept_quality;
const internalNames = data.accept_format.split(",");
const displayNames = data.accept_description;
const formats = [];
while (qualities.length > 0)
{
const format = new VideoFormat(
qualities.pop(),
internalNames.pop(),
displayNames.pop()
);
formats.push(format);
}
resolve(formats);
});
xhr.addEventListener("error", () => reject(`获取清晰度信息失败.`));
xhr.withCredentials = true;
xhr.open("GET", url);
xhr.send();
});
}
}
class VideoDownloadInfoFragment
{
constructor(length, size, url, backupUrls)
{
this.length = length;
this.size = size;
this.url = url;
this.backupUrls = backupUrls;
}
}
class VideoDownloadInfo
{
constructor(format, fragments)
{
this.format = format;
this.fragments = fragments || [];
this.progress = null;
this.loaded = 0;
this.totalSize = null;
this.workingXhr = null;
}
fetchVideoInfo()
{
return new Promise((resolve, reject) =>
{
const url = `https://api.bilibili.com/x/player/playurl?avid=${pageData.aid}&cid=${pageData.cid}&qn=${this.format.quality}&otype=json`;
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () =>
{
const data = JSON.parse(xhr.responseText.replace(/http:/g, "https:")).data;
if (data.quality !== this.format.quality)
{
reject("获取下载链接失败, 请确认当前账号有下载权限后重试.");
}
const urls = data.durl;
this.fragments = urls.map(it => new VideoDownloadInfoFragment(
it.length, it.size,
it.url,
it.backup_url
));
// if (this.fragments.length > 1)
// {
// reject("暂不支持分段视频的下载.");
// }
resolve(this.fragments);
});
xhr.withCredentials = true;
xhr.open("GET", url);
xhr.send();
});
}
cancelDownload()
{
if (this.workingXhr)
{
this.workingXhr.abort();
}
}
downloadUrl(url)
{
return new Promise((resolve, reject) =>
{
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "arraybuffer";
xhr.withCredentials = false;
xhr.addEventListener("progress", (e) =>
{
this.progress && this.progress((this.loaded + e.loaded) / this.totalSize);
});
xhr.addEventListener("load", () =>
{
if (xhr.status === 200)
{
resolve(xhr.response);
}
else
{
reject(`请求失败.`);
}
});
xhr.addEventListener("abort", () => reject("下载已取消."));
xhr.addEventListener("error", () => reject(`下载失败.`));
xhr.send();
this.workingXhr = xhr;
});
}
copyUrl()
{
const urls = this.fragments.map(it => it.url).reduce((acc, it) => acc + "\r\n" + it);
GM_setClipboard(urls, "text");
}
async download()
{
const downloadedData = [];
this.loaded = 0;
this.totalSize = this.fragments.map(it => it.size).reduce((acc, it) => acc + it);
for (const fragment of this.fragments)
{
const data = await this.downloadUrl(fragment.url);
this.loaded += fragment.size;
downloadedData.push(data);
}
if (downloadedData.length < 1)
{
throw new Error("下载失败.");
}
let blob = null;
let filename = null;
const extension = fragment => (fragment || this.fragments[0]).url.indexOf(".flv") !== -1 ? ".flv" : ".mp4";
if (downloadedData.length === 1)
{
const [data] = downloadedData;
blob = new Blob([data], {
type: extension() === ".flv" ? "video/x-flv" : "video/mp4"
});
filename = document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili", "") + extension();
}
else
{
const zip = new JSZip();
const title = document.title.replace("_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili", "");
downloadedData.forEach((data, index) =>
{
zip.file(`${title} - ${index + 1}${extension(this.fragments[index])}`, data);
});
blob = await zip.generateAsync({ type: "blob" });
filename = title + ".zip";
}
const blobUrl = URL.createObjectURL(blob);
const oldBlobUrl = $("a#video-complete").attr("href");
if (oldBlobUrl)
{
URL.revokeObjectURL(oldBlobUrl);
}
this.progress && this.progress(0);
return {
url: blobUrl,
filename: filename
};
}
}
function loadWidget()
{
(async () =>
{
let aid = (unsafeWindow || window).aid;
let cid = (unsafeWindow || window).cid;
if (aid === undefined || cid === undefined)
{
const aidMatch = document.URL.match(/\/av(\d+)/);
const epMatch = document.URL.match(/\/ep(\d+)/);
if (aidMatch && aidMatch[1])
{
const info = await new VideoInfo(aidMatch[1]).fetchInfo();
aid = info.aid;
cid = info.cid;
}
// TODO: Download bangumi, the legacy method not work...
// else if (epMatch && epMatch[1])
// {
// const info = await new BangumiInfo(epMatch[1]).fetchInfo();
// aid = info.aid;
// cid = info.cid;
// }
}
return [aid, cid];
})().then(result =>
{
const [aid, cid] = result;
if (aid === undefined || cid === undefined)
{
return;
}
pageData.aid = aid;
pageData.cid = cid;
VideoFormat.availableFormats.then((formats) =>
{
let [selectedFormat] = formats;
const getVideoInfo = () => selectedFormat.downloadInfo().catch(error =>
{
$(".download-video-panel").addClass("error");
$(".video-error").text(error);
});
async function download()
{
if (!selectedFormat)
{
return;
}
$(".download-video-panel")
.removeClass("action")
.addClass("progress");
const info = await getVideoInfo();
info.progress = percent =>
{
$(".download-progress-value").text(`${fixed(percent * 100)}`);
$(".download-progress-foreground").css("transform", `scaleX(${percent})`);
};
document.querySelector(".download-progress-cancel>span").onclick = () => info.cancelDownload();
const result = await info.download()
.catch(error =>
{
$(".download-video-panel").addClass("error");
$(".video-error").text(error);
});
if (!result) // canceled or other errors
{
return;
}
const completeLink = document.getElementById("video-complete");
completeLink.setAttribute("href", result.url);
completeLink.setAttribute("download", result.filename);
completeLink.click();
$(".download-video-panel")
.removeClass("progress")
.addClass("quality");
}
async function copyLink()
{
if (!selectedFormat)
{
return;
}
const info = await getVideoInfo();
info.copyUrl();
Toast.success("已复制链接到剪贴板.", "复制链接", 3000);
$(".download-video-panel")
.removeClass("action")
.addClass("quality");
}
$(".video-action>#video-action-download").on("click", download);
$(".video-action>#video-action-copy").on("click", copyLink);
formats.forEach(format =>
{
$(`<li>${format.displayName}</li>`)
.on("click", () =>
{
selectedFormat = format;
$(".download-video-panel")
.removeClass("quality")
.addClass("action");
})
.prependTo("ol.video-quality");
});
resources.applyStyle("downloadVideoStyle");
$("#download-video").on("click", () =>
{
$(".download-video-panel").toggleClass("opened");
}).parent().removeClass("hidden");
});
$(".video-error").on("click", () =>
{
$(".video-error").text("");
$(".download-video-panel")
.removeClass("error")
.removeClass("progress")
.addClass("quality");
});
});
}
return {
settingsWidget: {
category: "视频与直播",
content: resources.data.downloadVideoDom.text,
success: loadWidget
}
};
};
})();

View File

@ -0,0 +1,107 @@
.download-video-panel.opened
{
transform: scaleY(1);
}
.download-video-panel
{
position: absolute;
top: calc(100% + 8px);
transition: all .16s ease-out;
transform-origin: top;
transform: scaleY(0);
background: white;
border-radius: 4px;
box-shadow: 0px 3px 20px 2px #0004;
z-index: 100;
}
.gui-settings-content ol.video-quality li,
.video-action>div
{
cursor: pointer;
align-items: center;
margin: 0;
padding: 8px 16px;
border-radius: 4px;
transition: all .2s ease-out;
}
.video-action>div
{
padding: 12px 24px;
}
.gui-settings-content ol.video-quality li:hover,
.video-action>div:hover
{
background: rgba(0,0,0,0.16);
}
.video-quality,
.video-progress,
.video-action,
.video-error
{
display: none;
}
.download-video-panel.quality:not(.error) .video-quality,
.download-video-panel.progress:not(.error) .video-progress,
.download-video-panel.action:not(.error) .video-action,
.download-video-panel.error .video-error
{
display: block;
}
.download-progress-text
{
display: flex;
}
.download-progress-title
{
flex: 1 0 0;
}
.download-progress-background
{
background-color: #8884;
height: 4px;
width: 100%;
margin-top: 4px;
}
.download-progress-foreground
{
background-color: $customStyleColor;
transform-origin: left;
transition: all .2s ease-out;
transform: scaleX(0);
height: 100%;
width: 100%;
}
.download-progress-cancel
{
margin-top: 8px;
display: flex;
justify-content: center;
}
.download-progress-cancel>span
{
border-radius: 4px;
background-color: #8884;
padding: 4px 8px;
cursor: pointer;
}
.download-progress-cancel>span:hover
{
opacity: .9;
}
.download-progress-cancel>span:active
{
opacity: .8;
}
.video-error,
.video-progress
{
padding: 12px;
}
.video-progress
{
min-width: 160px;
}
#video-complete
{
display: none;
}

77
video/video-info.js Normal file
View File

@ -0,0 +1,77 @@
(() =>
{
return () =>
{
class VideoInfo
{
constructor(aid)
{
this.aid = aid;
}
async fetchInfo()
{
const json = JSON.parse(await downloadText(`https://api.bilibili.com/x/web-interface/view?aid=${this.aid}`));
if (json.code !== 0)
{
throw new Error(json.message);
}
const data = json.data;
this.cid = data.cid;
this.pageCount = data.videos;
this.coverUrl = data.pic;
this.tagId = data.tid;
this.tagName = data.tname;
this.title = data.title;
this.description = data.desc;
this.up = {
uid: data.owner.mid,
name: data.owner.name,
faceUrl: data.owner.face
};
this.pages = data.pages.map(it =>
{
return {
cid: it.cid,
title: it.part,
pageNumber: it.page
};
});
return this;
}
}
class BangumiInfo
{
constructor(ep)
{
this.ep = ep;
this.videos = [];
}
async fetchInfo()
{
const data = await downloadText(`https://www.bilibili.com/bangumi/play/ep${this.ep}/`);
const json = JSON.parse(data.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){/)[1]);
this.title = json.mediaInfo.title;
this.cover = json.mediaInfo.cover;
this.squareCover = json.mediaInfo.square_cover;
this.aid = json.epInfo.aid;
this.cid = json.epInfo.cid;
this.videos = json.epList.map(async (it) =>
{
return {
title: it.index_title,
aid: it.aid,
cid: it.cid,
info: await new VideoInfo(it.aid).fetchInfo()
};
});
return this;
}
}
return {
export: {
VideoInfo: VideoInfo,
BangumiInfo: BangumiInfo
}
};
};
})();

View File

@ -41,31 +41,31 @@
show()
{
this.viewer.addClass("opened");
$("html,body").addClass("image-viewer-opened");
// $("html,body").addClass("image-viewer-opened");
}
hide()
{
this.viewer.removeClass("opened");
$("html,body").removeClass("image-viewer-opened");
// $("html,body").removeClass("image-viewer-opened");
}
}
if ($("meta[itemprop='image']").length > 0)
if ($("meta[itemprop='image'],meta[property='og:image']").length > 0)
{
return {
settingsWidget: {
after: () => $("span.settings-category").filter((_, e) => e.innerHTML === "视频与直播").parent(),
content: `<li class="indent-center hidden">
category: "视频与直播",
content: `<div class="hidden">
<button
class="gui-settings-button"
title="查看当前视频的封面"
id="view-video-cover">
查看封面
</button>
</li>`,
</div>`,
success: () =>
{
new SpinQuery(() => $("meta[itemprop='image']"),
new SpinQuery(() => $("meta[itemprop='image'],meta[property='og:image']"),
metaData => metaData.length > 0 && metaData.prop("content"),
metaData =>
{
@ -83,15 +83,15 @@
{
return {
settingsWidget: {
after: () => $("span.settings-category").filter((_, e) => e.innerHTML === "视频与直播").parent(),
content: `<li class="indent-center hidden">
category: "视频与直播",
content: `<div class="hidden">
<button
class="gui-settings-button"
title="查看当前直播的封面"
id="view-live-cover">
查看封面
</button>
</li>`,
</div>`,
success: () =>
{
SpinQuery.any(() => $(".header-info-ctnr .room-cover"), coverLink =>