mirror of
https://github.com/xfgryujk/blivechat.git
synced 2025-01-15 23:00:32 +08:00
完成配置保存和读取
This commit is contained in:
parent
22e8f88533
commit
920e6fff96
275
frontend/src/api/config.js
Normal file
275
frontend/src/api/config.js
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const DEFAULT_CSS = `@import url("https://fonts.googleapis.com/css?family=Changa%20One");
|
||||||
|
@import url("https://fonts.googleapis.com/css?family=Imprima");
|
||||||
|
/* @import url("https://fonts.lug.ustc.edu.cn/css?family=Changa%20One"); */
|
||||||
|
/* @import url("https://fonts.lug.ustc.edu.cn/css?family=Imprima"); */
|
||||||
|
|
||||||
|
/* Background colors*/
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: rgba(0,0,0,0);
|
||||||
|
}
|
||||||
|
/* Transparent background. */
|
||||||
|
yt-live-chat-renderer {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
yt-live-chat-text-message-renderer,
|
||||||
|
yt-live-chat-text-message-renderer[is-highlighted] {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer[author-type="owner"],
|
||||||
|
yt-live-chat-text-message-renderer[author-type="owner"][is-highlighted] {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer[author-type="moderator"],
|
||||||
|
yt-live-chat-text-message-renderer[author-type="moderator"][is-highlighted] {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer[author-type="member"],
|
||||||
|
yt-live-chat-text-message-renderer[author-type="member"][is-highlighted] {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
yt-live-chat-author-chip #author-name {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
/* Outlines */
|
||||||
|
yt-live-chat-renderer * {
|
||||||
|
text-shadow: -2px -2px #000000,-2px -1px #000000,-2px 0px #000000,-2px 1px #000000,-2px 2px #000000,-1px -2px #000000,-1px -1px #000000,-1px 0px #000000,-1px 1px #000000,-1px 2px #000000,0px -2px #000000,0px -1px #000000,0px 0px #000000,0px 1px #000000,0px 2px #000000,1px -2px #000000,1px -1px #000000,1px 0px #000000,1px 1px #000000,1px 2px #000000,2px -2px #000000,2px -1px #000000,2px 0px #000000,2px 1px #000000,2px 2px #000000;
|
||||||
|
font-family: "Imprima";
|
||||||
|
font-size: 18px !important;
|
||||||
|
line-height: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer #content,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #content {
|
||||||
|
overflow: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide scrollbar. */
|
||||||
|
yt-live-chat-item-list-renderer #items{
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-item-list-renderer #item-scroller{
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide header and input. */
|
||||||
|
yt-live-chat-header-renderer,
|
||||||
|
yt-live-chat-message-input-renderer {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reduce side padding. */
|
||||||
|
yt-live-chat-text-message-renderer,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer {
|
||||||
|
padding-left: 4px !important;
|
||||||
|
padding-right: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-paid-message-renderer #header {
|
||||||
|
padding-left: 4px !important;
|
||||||
|
padding-right: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avatars. */
|
||||||
|
yt-live-chat-text-message-renderer #author-photo,
|
||||||
|
yt-live-chat-paid-message-renderer #author-photo,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #author-photo {
|
||||||
|
|
||||||
|
width: 24px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
border-radius: 24px !important;
|
||||||
|
margin-right: 6px !important;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide badges. */
|
||||||
|
yt-live-chat-text-message-renderer #author-badges {
|
||||||
|
display: none !important;
|
||||||
|
vertical-align: text-top !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timestamps. */
|
||||||
|
yt-live-chat-text-message-renderer #timestamp {
|
||||||
|
|
||||||
|
color: #999999 !important;
|
||||||
|
font-family: "Imprima";
|
||||||
|
font-size: 16px !important;
|
||||||
|
line-height: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Badges. */
|
||||||
|
yt-live-chat-text-message-renderer #author-name[type="owner"],
|
||||||
|
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="owner"] {
|
||||||
|
color: #ffd600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer #author-name[type="moderator"],
|
||||||
|
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="moderator"] {
|
||||||
|
color: #5e84f1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer #author-name[type="member"],
|
||||||
|
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="member"] {
|
||||||
|
color: #0f9d58 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Channel names. */
|
||||||
|
yt-live-chat-text-message-renderer #author-name {
|
||||||
|
color: #cccccc !important;
|
||||||
|
font-family: "Changa One";
|
||||||
|
font-size: 20px !important;
|
||||||
|
line-height: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer #author-name::after {
|
||||||
|
content: ":";
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Messages. */
|
||||||
|
yt-live-chat-text-message-renderer #message,
|
||||||
|
yt-live-chat-text-message-renderer #message * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-family: "Imprima";
|
||||||
|
font-size: 18px !important;
|
||||||
|
line-height: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SuperChat/Fan Funding Messages. */
|
||||||
|
yt-live-chat-paid-message-renderer #author-name,
|
||||||
|
yt-live-chat-paid-message-renderer #author-name *,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #event-text,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #event-text * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-family: "Changa One";
|
||||||
|
font-size: 20px !important;
|
||||||
|
line-height: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-paid-message-renderer #purchase-amount,
|
||||||
|
yt-live-chat-paid-message-renderer #purchase-amount *,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #detail-text,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer #detail-text * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-family: "Imprima";
|
||||||
|
font-size: 18px !important;
|
||||||
|
line-height: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-paid-message-renderer #content,
|
||||||
|
yt-live-chat-paid-message-renderer #content * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-family: "Imprima";
|
||||||
|
font-size: 18px !important;
|
||||||
|
line-height: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-paid-message-renderer {
|
||||||
|
margin: 4px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-legacy-paid-message-renderer {
|
||||||
|
background-color: #0f9d58 !important;
|
||||||
|
margin: 4px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer a,
|
||||||
|
yt-live-chat-legacy-paid-message-renderer a {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-text-message-renderer[is-deleted],
|
||||||
|
yt-live-chat-legacy-paid-message-renderer[is-deleted] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-ticker-renderer {
|
||||||
|
background-color: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
yt-live-chat-ticker-renderer {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
yt-live-chat-ticker-paid-message-item-renderer,
|
||||||
|
yt-live-chat-ticker-paid-message-item-renderer *,
|
||||||
|
yt-live-chat-ticker-sponsor-item-renderer,
|
||||||
|
yt-live-chat-ticker-sponsor-item-renderer * {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-family: "Imprima";
|
||||||
|
}
|
||||||
|
|
||||||
|
yt-live-chat-mode-change-message-renderer,
|
||||||
|
yt-live-chat-viewer-engagement-message-renderer,
|
||||||
|
yt-live-chat-restricted-participation-renderer {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const DEFAULT_CONFIG = {
|
||||||
|
minGiftPrice: 6.911, // $1
|
||||||
|
mergeSimilarDanmaku: true,
|
||||||
|
|
||||||
|
blockGiftDanmaku: true,
|
||||||
|
blockLevel: 0,
|
||||||
|
blockNewbie: true,
|
||||||
|
blockNotMobileVerified: true,
|
||||||
|
blockKeywords: '',
|
||||||
|
blockUsers: '',
|
||||||
|
|
||||||
|
css: DEFAULT_CSS
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeConfig (config) {
|
||||||
|
let res = {}
|
||||||
|
for (let i in DEFAULT_CONFIG) {
|
||||||
|
res[i] = i in config ? config[i] : DEFAULT_CONFIG[i]
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLocalConfig (config) {
|
||||||
|
config = mergeConfig(config)
|
||||||
|
window.localStorage.config = JSON.stringify(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLocalConfig () {
|
||||||
|
if (!window.localStorage.config) {
|
||||||
|
return DEFAULT_CONFIG
|
||||||
|
}
|
||||||
|
return mergeConfig(JSON.parse(window.localStorage.config))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createRemoteConfig (config) {
|
||||||
|
config = mergeConfig(config)
|
||||||
|
return (await axios.post('/config', config)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setRemoteConfig (id, config) {
|
||||||
|
config = mergeConfig(config)
|
||||||
|
return (await axios.put(`/config/${id}`, config)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRemoteConfig (id) {
|
||||||
|
let config = (await axios.get(`/config/${id}`)).data
|
||||||
|
return mergeConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
setLocalConfig,
|
||||||
|
getLocalConfig,
|
||||||
|
createRemoteConfig,
|
||||||
|
setRemoteConfig,
|
||||||
|
getRemoteConfig
|
||||||
|
}
|
@ -207,220 +207,3 @@ yt-live-chat-ticker-paid-message-item-renderer #fake-avatar {
|
|||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 以下为自动生成:https://chatv2.septapus.com/ */
|
|
||||||
|
|
||||||
/* @import url("https://fonts.googleapis.com/css?family=Changa%20One"); */
|
|
||||||
/* @import url("https://fonts.googleapis.com/css?family=Imprima"); */
|
|
||||||
@import url("https://fonts.lug.ustc.edu.cn/css?family=Changa%20One");
|
|
||||||
@import url("https://fonts.lug.ustc.edu.cn/css?family=Imprima");
|
|
||||||
|
|
||||||
/* Background colors*/
|
|
||||||
body {
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: rgba(0,0,0,0);
|
|
||||||
}
|
|
||||||
/* Transparent background. */
|
|
||||||
yt-live-chat-renderer {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
yt-live-chat-text-message-renderer,
|
|
||||||
yt-live-chat-text-message-renderer[is-highlighted] {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer[author-type="owner"],
|
|
||||||
yt-live-chat-text-message-renderer[author-type="owner"][is-highlighted] {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer[author-type="moderator"],
|
|
||||||
yt-live-chat-text-message-renderer[author-type="moderator"][is-highlighted] {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer[author-type="member"],
|
|
||||||
yt-live-chat-text-message-renderer[author-type="member"][is-highlighted] {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
yt-live-chat-author-chip #author-name {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
/* Outlines */
|
|
||||||
yt-live-chat-renderer * {
|
|
||||||
text-shadow: -2px -2px #000000,-2px -1px #000000,-2px 0px #000000,-2px 1px #000000,-2px 2px #000000,-1px -2px #000000,-1px -1px #000000,-1px 0px #000000,-1px 1px #000000,-1px 2px #000000,0px -2px #000000,0px -1px #000000,0px 0px #000000,0px 1px #000000,0px 2px #000000,1px -2px #000000,1px -1px #000000,1px 0px #000000,1px 1px #000000,1px 2px #000000,2px -2px #000000,2px -1px #000000,2px 0px #000000,2px 1px #000000,2px 2px #000000;
|
|
||||||
font-family: "Imprima";
|
|
||||||
font-size: 18px !important;
|
|
||||||
line-height: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer #content,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #content {
|
|
||||||
overflow: initial !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide scrollbar. */
|
|
||||||
yt-live-chat-item-list-renderer #items{
|
|
||||||
overflow: hidden !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-item-list-renderer #item-scroller{
|
|
||||||
overflow: hidden !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide header and input. */
|
|
||||||
yt-live-chat-header-renderer,
|
|
||||||
yt-live-chat-message-input-renderer {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reduce side padding. */
|
|
||||||
yt-live-chat-text-message-renderer,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer {
|
|
||||||
padding-left: 4px !important;
|
|
||||||
padding-right: 4px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-paid-message-renderer #header {
|
|
||||||
padding-left: 4px !important;
|
|
||||||
padding-right: 4px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Avatars. */
|
|
||||||
yt-live-chat-text-message-renderer #author-photo,
|
|
||||||
yt-live-chat-paid-message-renderer #author-photo,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #author-photo {
|
|
||||||
|
|
||||||
width: 24px !important;
|
|
||||||
height: 24px !important;
|
|
||||||
border-radius: 24px !important;
|
|
||||||
margin-right: 6px !important;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide badges. */
|
|
||||||
yt-live-chat-text-message-renderer #author-badges {
|
|
||||||
display: none !important;
|
|
||||||
vertical-align: text-top !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Timestamps. */
|
|
||||||
yt-live-chat-text-message-renderer #timestamp {
|
|
||||||
|
|
||||||
color: #999999 !important;
|
|
||||||
font-family: "Imprima";
|
|
||||||
font-size: 16px !important;
|
|
||||||
line-height: 16px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Badges. */
|
|
||||||
yt-live-chat-text-message-renderer #author-name[type="owner"],
|
|
||||||
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="owner"] {
|
|
||||||
color: #ffd600 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer #author-name[type="moderator"],
|
|
||||||
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="moderator"] {
|
|
||||||
color: #5e84f1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer #author-name[type="member"],
|
|
||||||
yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer[type="member"] {
|
|
||||||
color: #0f9d58 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Channel names. */
|
|
||||||
yt-live-chat-text-message-renderer #author-name {
|
|
||||||
color: #cccccc !important;
|
|
||||||
font-family: "Changa One";
|
|
||||||
font-size: 20px !important;
|
|
||||||
line-height: 20px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer #author-name::after {
|
|
||||||
content: ":";
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Messages. */
|
|
||||||
yt-live-chat-text-message-renderer #message,
|
|
||||||
yt-live-chat-text-message-renderer #message * {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-family: "Imprima";
|
|
||||||
font-size: 18px !important;
|
|
||||||
line-height: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* SuperChat/Fan Funding Messages. */
|
|
||||||
yt-live-chat-paid-message-renderer #author-name,
|
|
||||||
yt-live-chat-paid-message-renderer #author-name *,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #event-text,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #event-text * {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-family: "Changa One";
|
|
||||||
font-size: 20px !important;
|
|
||||||
line-height: 20px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-paid-message-renderer #purchase-amount,
|
|
||||||
yt-live-chat-paid-message-renderer #purchase-amount *,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #detail-text,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer #detail-text * {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-family: "Imprima";
|
|
||||||
font-size: 18px !important;
|
|
||||||
line-height: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-paid-message-renderer #content,
|
|
||||||
yt-live-chat-paid-message-renderer #content * {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-family: "Imprima";
|
|
||||||
font-size: 18px !important;
|
|
||||||
line-height: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-paid-message-renderer {
|
|
||||||
margin: 4px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-legacy-paid-message-renderer {
|
|
||||||
background-color: #0f9d58 !important;
|
|
||||||
margin: 4px 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer a,
|
|
||||||
yt-live-chat-legacy-paid-message-renderer a {
|
|
||||||
text-decoration: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-text-message-renderer[is-deleted],
|
|
||||||
yt-live-chat-legacy-paid-message-renderer[is-deleted] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-ticker-renderer {
|
|
||||||
background-color: transparent !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
}
|
|
||||||
yt-live-chat-ticker-renderer {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
yt-live-chat-ticker-paid-message-item-renderer,
|
|
||||||
yt-live-chat-ticker-paid-message-item-renderer *,
|
|
||||||
yt-live-chat-ticker-sponsor-item-renderer,
|
|
||||||
yt-live-chat-ticker-sponsor-item-renderer * {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-family: "Imprima";
|
|
||||||
}
|
|
||||||
|
|
||||||
yt-live-chat-mode-change-message-renderer,
|
|
||||||
yt-live-chat-viewer-engagement-message-renderer,
|
|
||||||
yt-live-chat-restricted-participation-renderer {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 1.1 KiB |
@ -2,6 +2,7 @@ import Vue from 'vue'
|
|||||||
import VueRouter from 'vue-router'
|
import VueRouter from 'vue-router'
|
||||||
import ElementUI from 'element-ui'
|
import ElementUI from 'element-ui'
|
||||||
import 'element-ui/lib/theme-chalk/index.css'
|
import 'element-ui/lib/theme-chalk/index.css'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import Layout from './layout'
|
import Layout from './layout'
|
||||||
@ -10,6 +11,11 @@ import StyleGenerator from './views/StyleGenerator.vue'
|
|||||||
import Room from './views/Room'
|
import Room from './views/Room'
|
||||||
import NotFound from './views/NotFound.vue'
|
import NotFound from './views/NotFound.vue'
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
// 开发时使用localhost:80
|
||||||
|
axios.defaults.baseURL = 'http://localhost'
|
||||||
|
}
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
Vue.use(ElementUI)
|
Vue.use(ElementUI)
|
||||||
|
|
||||||
|
@ -43,52 +43,68 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<el-form-item label="房间URL" v-show="roomUrl">
|
||||||
|
<el-input ref="roomUrlInput" readonly :value="roomUrl" style="width: calc(100% - 6em); margin-right: 1em;"></el-input>
|
||||||
|
<el-button type="primary" @click="copyUrl">复制</el-button>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="enterRoom">进入房间</el-button>
|
<el-button type="primary" @click="saveConfig()">保存配置</el-button>
|
||||||
<el-button type="primary" @click="popupRoom">弹出房间</el-button>
|
<el-button type="primary" :disabled="!roomUrl" @click="enterRoom">进入房间</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import config from '@/api/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
roomId: parseInt(window.localStorage.roomId || '1'),
|
roomId: parseInt(window.localStorage.roomId || '1'),
|
||||||
minGiftPrice: 6.911, // $1
|
...config.getLocalConfig()
|
||||||
mergeSimilarDanmaku: true,
|
},
|
||||||
|
roomUrl: ''
|
||||||
blockGiftDanmaku: true,
|
|
||||||
blockLevel: 0,
|
|
||||||
blockNewbie: true,
|
|
||||||
blockNotMobileVerified: true,
|
|
||||||
blockKeywords: '',
|
|
||||||
blockUsers: '',
|
|
||||||
|
|
||||||
css: ''
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
saveConfig(callback) {
|
saveConfig() {
|
||||||
this.$refs.form.validate(valid => {
|
this.$refs.form.validate(async valid => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
window.localStorage.roomId = this.form.roomId
|
window.localStorage.roomId = this.form.roomId
|
||||||
callback()
|
config.setLocalConfig(this.form)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (window.localStorage.configId) {
|
||||||
|
try {
|
||||||
|
await config.setRemoteConfig(window.localStorage.configId, this.form)
|
||||||
|
} catch (e) { // 404
|
||||||
|
window.localStorage.configId = (await config.createRemoteConfig(this.form)).id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.localStorage.configId = (await config.createRemoteConfig(this.form)).id
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error('保存失败:' + e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$message({message: '保存成功', type: 'success'})
|
||||||
|
|
||||||
|
let resolved = this.$router.resolve({name: 'room', params: {roomId: this.form.roomId},
|
||||||
|
query: {config_id: window.localStorage.configId}})
|
||||||
|
this.roomUrl = `http://${window.location.host}${resolved.href}`
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
enterRoom() {
|
enterRoom() {
|
||||||
this.saveConfig(() => this.$router.push({name: 'room', params: {roomId: this.form.roomId}}))
|
window.open(this.roomUrl, `room ${this.form.roomId}`, 'menubar=0,location=0,scrollbars=0,toolbar=0,width=600,height=600')
|
||||||
},
|
},
|
||||||
popupRoom() {
|
copyUrl() {
|
||||||
this.saveConfig(() => {
|
this.$refs.roomUrlInput.select()
|
||||||
let resolved = this.$router.resolve({name: 'room', params: {roomId: this.form.roomId}})
|
document.execCommand('Copy')
|
||||||
window.open(resolved.href, `room ${this.form.roomId}`, 'menubar=0,location=0,scrollbars=0,toolbar=0,width=600,height=600')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import config from '@/api/config'
|
||||||
import TextMessage from './TextMessage.vue'
|
import TextMessage from './TextMessage.vue'
|
||||||
import LegacyPaidMessage from './LegacyPaidMessage.vue'
|
import LegacyPaidMessage from './LegacyPaidMessage.vue'
|
||||||
import PaidMessage from './PaidMessage.vue'
|
import PaidMessage from './PaidMessage.vue'
|
||||||
@ -50,13 +51,18 @@ export default {
|
|||||||
PaidMessage
|
PaidMessage
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
let styleElement = document.createElement('style')
|
||||||
|
styleElement.innerText = config.DEFAULT_CONFIG.css
|
||||||
|
document.head.appendChild(styleElement)
|
||||||
return {
|
return {
|
||||||
|
config: config.DEFAULT_CONFIG,
|
||||||
|
styleElement,
|
||||||
websocket: null,
|
websocket: null,
|
||||||
messages: [],
|
messages: [],
|
||||||
nextId: 0
|
nextId: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
async created() {
|
||||||
// 开发时使用localhost:80
|
// 开发时使用localhost:80
|
||||||
const url = process.env.NODE_ENV === 'development' ? 'ws://localhost/chat' : `ws://${window.location.host}/chat`
|
const url = process.env.NODE_ENV === 'development' ? 'ws://localhost/chat' : `ws://${window.location.host}/chat`
|
||||||
this.websocket = new WebSocket(url)
|
this.websocket = new WebSocket(url)
|
||||||
@ -85,7 +91,7 @@ export default {
|
|||||||
break
|
break
|
||||||
case COMMAND_ADD_GIFT:
|
case COMMAND_ADD_GIFT:
|
||||||
price = body.data.totalCoin / 1000
|
price = body.data.totalCoin / 1000
|
||||||
if (price < 6.911) // 丢人
|
if (price < this.config.minGiftPrice) // 丢人
|
||||||
break
|
break
|
||||||
message = {
|
message = {
|
||||||
id: this.nextId++,
|
id: this.nextId++,
|
||||||
@ -112,8 +118,18 @@ export default {
|
|||||||
this.messages.shift()
|
this.messages.shift()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.$route.query.config_id) {
|
||||||
|
try {
|
||||||
|
this.config = await config.getRemoteConfig(this.$route.query.config_id)
|
||||||
|
this.styleElement.innerText = this.config.css
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error('获取配置失败:' + e)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
document.head.removeChild(this.styleElement)
|
||||||
this.websocket.close()
|
this.websocket.close()
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
|
18
main.py
18
main.py
@ -7,20 +7,15 @@ import os
|
|||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
import tornado.web
|
import tornado.web
|
||||||
|
|
||||||
import chat
|
import views.chat
|
||||||
|
import views.config
|
||||||
|
import views.main
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
WEB_ROOT = os.path.join(os.path.dirname(__file__), 'frontend', 'dist')
|
WEB_ROOT = os.path.join(os.path.dirname(__file__), 'frontend', 'dist')
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyAbstractClass
|
|
||||||
class MainHandler(tornado.web.StaticFileHandler):
|
|
||||||
"""为了使用Vue Router的history模式,把所有请求转发到index.html"""
|
|
||||||
async def get(self, *args, **kwargs):
|
|
||||||
await super().get('index.html', *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='用于OBS的仿YouTube风格的bilibili直播聊天层')
|
parser = argparse.ArgumentParser(description='用于OBS的仿YouTube风格的bilibili直播聊天层')
|
||||||
parser.add_argument('--host', help='服务器host,默认为127.0.0.1', default='127.0.0.1')
|
parser.add_argument('--host', help='服务器host,默认为127.0.0.1', default='127.0.0.1')
|
||||||
@ -37,10 +32,13 @@ def main():
|
|||||||
|
|
||||||
app = tornado.web.Application(
|
app = tornado.web.Application(
|
||||||
[
|
[
|
||||||
(r'/chat', chat.ChatHandler),
|
(r'/chat', views.chat.ChatHandler),
|
||||||
|
(r'/config', views.config.ConfigsHandler),
|
||||||
|
(r'/config/(.+)', views.config.ConfigHandler),
|
||||||
|
|
||||||
(r'/((css|img|js)/.*)', tornado.web.StaticFileHandler, {'path': WEB_ROOT}),
|
(r'/((css|img|js)/.*)', tornado.web.StaticFileHandler, {'path': WEB_ROOT}),
|
||||||
(r'/(favicon\.ico)', tornado.web.StaticFileHandler, {'path': WEB_ROOT}),
|
(r'/(favicon\.ico)', tornado.web.StaticFileHandler, {'path': WEB_ROOT}),
|
||||||
(r'/.*', MainHandler, {'path': WEB_ROOT})
|
(r'/.*', views.main.MainHandler, {'path': WEB_ROOT})
|
||||||
],
|
],
|
||||||
websocket_ping_interval=30,
|
websocket_ping_interval=30,
|
||||||
debug=args.debug,
|
debug=args.debug,
|
||||||
|
28
views/base.py
Normal file
28
views/base.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAbstractClass
|
||||||
|
class ApiHandler(tornado.web.RequestHandler):
|
||||||
|
def set_default_headers(self):
|
||||||
|
# 跨域测试用
|
||||||
|
if not self.application.settings['debug']:
|
||||||
|
return
|
||||||
|
self.set_header('Access-Control-Allow-Origin', '*')
|
||||||
|
self.set_header('Access-Control-Allow-Methods', 'OPTIONS, PUT, POST, GET, DELETE')
|
||||||
|
if 'Access-Control-Request-Headers' in self.request.headers:
|
||||||
|
self.set_header('Access-Control-Allow-Headers',
|
||||||
|
self.request.headers['Access-Control-Request-Headers'])
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
if self.request.headers.get('Content-Type', '').startswith('application/json'):
|
||||||
|
self.json_args = json.loads(self.request.body)
|
||||||
|
else:
|
||||||
|
self.json_args = None
|
||||||
|
|
||||||
|
async def options(self, *_args, **_kwargs):
|
||||||
|
# 跨域测试用
|
||||||
|
self.set_status(204 if self.application.settings['debug'] else 405)
|
50
views/config.py
Normal file
50
views/config.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
import views.base
|
||||||
|
from typing import *
|
||||||
|
|
||||||
|
configs: Dict[str, dict] = {}
|
||||||
|
|
||||||
|
ALLOWED_FIELDS = (
|
||||||
|
'minGiftPrice', 'mergeSimilarDanmaku', 'blockGiftDanmaku', 'blockLevel',
|
||||||
|
'blockNewbie', 'blockNotMobileVerified', 'blockKeywords', 'blockUsers',
|
||||||
|
'css'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAbstractClass
|
||||||
|
class ConfigsHandler(views.base.ApiHandler):
|
||||||
|
async def post(self):
|
||||||
|
config_id = str(uuid.uuid4())
|
||||||
|
config = {
|
||||||
|
name: self.json_args[name] for name in ALLOWED_FIELDS
|
||||||
|
}
|
||||||
|
config['id'] = config_id
|
||||||
|
configs[config_id] = config
|
||||||
|
self.set_status(201)
|
||||||
|
self.write(config)
|
||||||
|
|
||||||
|
if len(configs) > 10000:
|
||||||
|
for _, key in zip(range(100), configs):
|
||||||
|
del configs[key]
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAbstractClass
|
||||||
|
class ConfigHandler(views.base.ApiHandler):
|
||||||
|
async def put(self, config_id):
|
||||||
|
config = configs.get(config_id, None)
|
||||||
|
if config is None:
|
||||||
|
self.set_status(404)
|
||||||
|
return
|
||||||
|
for name in ALLOWED_FIELDS:
|
||||||
|
config[name] = self.json_args[name]
|
||||||
|
self.write(config)
|
||||||
|
|
||||||
|
async def get(self, config_id):
|
||||||
|
config = configs.get(config_id, None)
|
||||||
|
if config is None:
|
||||||
|
self.set_status(404)
|
||||||
|
return
|
||||||
|
self.write(config)
|
10
views/main.py
Normal file
10
views/main.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import tornado.web
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyAbstractClass
|
||||||
|
class MainHandler(tornado.web.StaticFileHandler):
|
||||||
|
"""为了使用Vue Router的history模式,把所有请求转发到index.html"""
|
||||||
|
async def get(self, *args, **kwargs):
|
||||||
|
await super().get('index.html', *args, **kwargs)
|
Loading…
Reference in New Issue
Block a user