Bumping version

This commit is contained in:
ForgQi committed 2024-01-12 00:54:14 +08:00
1 parent 6892d019b3
commit 16303af983
10 files changed
+346 -198

No files matched your search

+2 -11
View File
@@ -19,6 +19,7 @@ import 'xgplayer/dist/index.min.css';
import FlvPlugin from "xgplayer-flv";
import FlvJsPlugin from 'xgplayer-flv.js'
import Players from "@/app/ui/Player";
import {humDate} from "@/app/lib/utils";
export default function Home() {
const { Header, Footer, Sider, Content } = Layout;
@@ -96,20 +97,10 @@ export default function Home() {
>
<main>
<Table size="small" columns={columns} dataSource={data?.map(res => {
const updateTime = new Date(res.updateTime * 1000)
//日期
const DD = String(updateTime.getDate()).padStart(2, '0'); // 获取日
const MM = String(updateTime.getMonth() + 1).padStart(2, '0'); //获取月份,1 月为 0
const yyyy = updateTime.getFullYear(); // 获取年
// 时间
const hh = String(updateTime.getHours()).padStart(2, '0'); //获取当前小时数(0-23)
const mm = String(updateTime.getMinutes()).padStart(2, '0'); //获取当前分钟数(0-59)
const ss = String(updateTime.getSeconds()).padStart(2, '0'); //获取当前秒数(0-59)
return {
...res,
size: (res.size / 1024 / 1024).toFixed(2) + ' MB',
updateTime: yyyy + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss
updateTime: humDate(res.updateTime)
}
})} />
</main>
+85
View File
@@ -0,0 +1,85 @@
'use client'
import {Layout, Nav, Table, Typography} from "@douyinfe/semi-ui";
import useSWR from "swr";
import {fetcher, FileList} from "@/app/lib/api-streamer";
import {JSXElementConstructor, Key, PromiseLikeOfReactNode, ReactElement, ReactNode, ReactPortal,
useState
} from "react";
import {IconCustomerSupport, IconVideoListStroked} from "@douyinfe/semi-icons";
import {humDate} from "@/app/lib/utils";
export default function Home() {
const {Header, Footer, Sider, Content} = Layout;
const {data: data, error, isLoading} = useSWR<any[]>("/v1/streamer-info", fetcher);
if (isLoading) {
return (<>Loading</>);
}
const {Text} = Typography;
const columns = [
{
title: '标题',
dataIndex: 'title',
render: (text: any, record: any, index: any) => {
return (
<Text strong>{text}</Text>
);
}
}, {
title: '名称',
dataIndex: 'name',
}, {
title: '链接',
dataIndex: 'url',
},
{
title: '封面',
dataIndex: 'live_cover_path',
},
{
title: '更新日期',
dataIndex: 'date',
render: (text: any, record: any, index: any) => {
return (<>{humDate(text)}</>);
},
sorter: (a: any, b: any) => (a.updateTime - b.updateTime > 0 ? 1 : -1),
},
];
const expandRowRender = (record: any, index: number | undefined) => {
return <>文件列表:{record.files.map((it: { id: Key | null | undefined; file: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | PromiseLikeOfReactNode | null | undefined; }) => {
return <div key={it.id}>&nbsp;&nbsp;文件名:{it.file}</div>;
})}</>;
};
return (<>
<Header style={{backgroundColor: 'var(--semi-color-bg-1)'}}>
<Nav style={{border: 'none'}}
header={<>
<div style={{
backgroundColor: 'rgb(250 102 76)',
borderRadius: 'var(--semi-border-radius-large)',
color: 'var(--semi-color-bg-0)',
display: 'flex',
padding: '6px'
}}><IconCustomerSupport size='large'/></div>
<h4 style={{marginLeft: '12px'}}>录播管理</h4></>}
mode="horizontal"
></Nav>
</Header>
<Content
style={{
paddingLeft: 12,
paddingRight: 12,
backgroundColor: 'var(--semi-color-bg-0)',
}}
>
<main>
<Table size="small"
rowKey="id"
columns={columns}
dataSource={data}
expandedRowRender={expandRowRender}
/>
</main>
</Content>
</>);
}
+9 -2
View File
@@ -6,7 +6,7 @@ import styles from "./page.module.css";
import {SetStateAction, useCallback, useMemo, useState} from "react";
import Link from "next/link";
import {
IconCloudStroked,
IconCloudStroked, IconCustomerSupport,
IconDoubleChevronLeft,
IconDoubleChevronRight,
IconMoon,
@@ -63,7 +63,13 @@ export default function RootLayout({children,}: { children: React.ReactNode }) {
padding: '4px'
}}><IconStar size='small'/></div>
},
// {itemKey: 'Job', text: '投稿管理', icon: <IconStar/>},
{itemKey: 'job', text: '直播历史', icon: <div style={{
backgroundColor: 'rgb(250 102 76)',
borderRadius: 'var(--semi-border-radius-medium)',
color: 'var(--semi-color-bg-0)',
display: 'flex',
padding: '4px'
}}><IconCustomerSupport size='small'/></div>},
// {
// text: '任务平台',
// icon: <IconSetting/>,
@@ -84,6 +90,7 @@ export default function RootLayout({children,}: { children: React.ReactNode }) {
dashboard: "/dashboard",
streamers: "/streamers",
"upload-manager": "/upload-manager",
job: "/job",
};
if (!routerMap[props.itemKey]) {
return itemElement;
+15 -1
View File
@@ -39,4 +39,18 @@ export const registerMediaQuery = (media: string, { match, unmatch, callInInit =
return (): void => mediaQueryList.removeListener(handlerMediaChange);
}
return () => undefined;
};
};
export const humDate = function (time: number) {
const updateTime = new Date(time * 1000)
//日期
const DD = String(updateTime.getDate()).padStart(2, '0'); // 获取日
const MM = String(updateTime.getMonth() + 1).padStart(2, '0'); //获取月份,1 月为 0
const yyyy = updateTime.getFullYear(); // 获取年
// 时间
const hh = String(updateTime.getHours()).padStart(2, '0'); //获取当前小时数(0-23)
const mm = String(updateTime.getMinutes()).padStart(2, '0'); //获取当前分钟数(0-59)
const ss = String(updateTime.getSeconds()).padStart(2, '0');
return yyyy + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss;
}
+139
View File
@@ -0,0 +1,139 @@
.shadow {
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
background-color: var(--semi-color-bg-0);
/*margin-left: 11px;*/
}
body[theme-mode=dark] .shadow {
box-shadow: var(--semi-shadow-elevated);
}
/*.container {*/
/* padding: 0 2rem;*/
/*}*/
/*.main {*/
/* min-height: 100vh;*/
/* padding: 4rem 0;*/
/* flex: 1;*/
/* display: flex;*/
/* flex-direction: column;*/
/* justify-content: center;*/
/* align-items: center;*/
/*}*/
/*.footer {*/
/* display: flex;*/
/* flex: 1;*/
/* padding: 2rem 0;*/
/* border-top: 1px solid #eaeaea;*/
/* justify-content: center;*/
/* align-items: center;*/
/*}*/
/*.footer a {*/
/* display: flex;*/
/* justify-content: center;*/
/* align-items: center;*/
/* flex-grow: 1;*/
/*}*/
/*.title a {*/
/* color: #0070f3;*/
/* text-decoration: none;*/
/*}*/
/*.title a:hover,*/
/*.title a:focus,*/
/*.title a:active {*/
/* text-decoration: underline;*/
/*}*/
/*.title {*/
/* margin: 0;*/
/* line-height: 1.15;*/
/* font-size: 4rem;*/
/*}*/
/*.title,*/
/*.description {*/
/* text-align: center;*/
/*}*/
/*.description {*/
/* margin: 4rem 0;*/
/* line-height: 1.5;*/
/* font-size: 1.5rem;*/
/*}*/
/*.code {*/
/* background: #fafafa;*/
/* border-radius: 5px;*/
/* padding: 0.75rem;*/
/* font-size: 1.1rem;*/
/* font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,*/
/* Bitstream Vera Sans Mono, Courier New, monospace;*/
/*}*/
/*.grid {*/
/* display: flex;*/
/* align-items: center;*/
/* justify-content: center;*/
/* flex-wrap: wrap;*/
/* max-width: 800px;*/
/*}*/
/*.card {*/
/* margin: 1rem;*/
/* padding: 1.5rem;*/
/* text-align: left;*/
/* color: inherit;*/
/* text-decoration: none;*/
/* border: 1px solid #eaeaea;*/
/* border-radius: 10px;*/
/* transition: color 0.15s ease, border-color 0.15s ease;*/
/* max-width: 300px;*/
/*}*/
/*.card:hover,*/
/*.card:focus,*/
/*.card:active {*/
/* color: #0070f3;*/
/* border-color: #0070f3;*/
/*}*/
/*.card h2 {*/
/* margin: 0 0 1rem 0;*/
/* font-size: 1.5rem;*/
/*}*/
/*.card p {*/
/* margin: 0;*/
/* font-size: 1.25rem;*/
/* line-height: 1.5;*/
/*}*/
/*.logo {*/
/* height: 1em;*/
/* margin-left: 0.5rem;*/
/*}*/
/*@media (max-width: 600px) {*/
/* .grid {*/
/* width: 100%;*/
/* flex-direction: column;*/
/* }*/
/*}*/
/*@media (prefers-color-scheme: dark) {*/
/* .card,*/
/* .footer {*/
/* border-color: #222;*/
/* }*/
/* .code {*/
/* background: #111;*/
/* }*/
/* .logo img {*/
/* filter: invert(1);*/
/* }*/
/*}*/
+79
View File
@@ -0,0 +1,79 @@
@import '~@douyinfe/semi-ui/dist/css/semi.min.css';
.semi-light-scrollbar::-webkit-scrollbar, .semi-light-scrollbar ::-webkit-scrollbar, ::-webkit-scrollbar {
width: 8px;
height: 8px
}
.semi-light-scrollbar::-webkit-scrollbar-track, .semi-light-scrollbar ::-webkit-scrollbar-track, ::-webkit-scrollbar-track {
background: transparent
}
.semi-light-scrollbar::-webkit-scrollbar-corner, .semi-light-scrollbar ::-webkit-scrollbar-corner, ::-webkit-scrollbar-corner {
background-color: transparent
}
.semi-light-scrollbar::-webkit-scrollbar-thumb, .semi-light-scrollbar ::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb {
border-radius: 6px;
background: transparent;
-webkit-transition: all 1s;
transition: all 1s
}
.semi-light-scrollbar:hover::-webkit-scrollbar-thumb, .semi-light-scrollbar :hover::-webkit-scrollbar-thumb, :hover::-webkit-scrollbar-thumb {
background: var(--semi-color-fill-2)
}
.semi-light-scrollbar::-webkit-scrollbar-thumb:hover, .semi-light-scrollbar ::-webkit-scrollbar-thumb:hover, ::-webkit-scrollbar-thumb:hover {
background: var(--semi-color-fill-1)
}
body::-webkit-scrollbar, html::-webkit-scrollbar {
width: 8px;
height: 8px
}
body::-webkit-scrollbar-track, html::-webkit-scrollbar-track {
background: transparent
}
body::-webkit-scrollbar-corner, html::-webkit-scrollbar-corner {
background-color: transparent
}
body::-webkit-scrollbar-thumb, html::-webkit-scrollbar-thumb {
border-radius: 6px;
background: var(--semi-color-fill-2)
}
body::-webkit-scrollbar-thumb:hover, html::-webkit-scrollbar-thumb:hover {
background: var(--semi-color-fill-1)
}
html,
body {
padding: 0;
margin: 0;
color: var(--semi-color-text-0);
background-color: var(--semi-color-bg-0);
/*font-family: var(font-family);*/
}
/*a {*/
/* color: inherit;*/
/* text-decoration: none;*/
/*}*/
/** {*/
/* box-sizing: border-box;*/
/*}*/
/*@media (prefers-color-scheme: dark) {*/
/* html {*/
/* color-scheme: dark;*/
/* }*/
/* body {*/
/* color: white;*/
/* background: black;*/
/* }*/
/*}*/
-179
View File
@@ -1,179 +0,0 @@
import {Button, Layout as SeLayout} from '@douyinfe/semi-ui';
import {Nav} from '@douyinfe/semi-ui';
import {
IconMoon,
IconSun,
IconCloudStroked,
IconSemiLogo,
IconUserCardVideo,
IconDoubleChevronLeft,
IconDoubleChevronRight, IconVideoListStroked
} from '@douyinfe/semi-icons';
import Link from "next/link";
import {useCallback, useMemo, useState} from "react";
import styles from '../styles/Home.module.css';
import { useRouter } from 'next/router';
export default function Layout({children}) {
const {Header, Footer, Sider, Content} = SeLayout;
const router = useRouter();
const renderWrapper = useCallback(({ itemElement, isSubNav, isInSubNav, props }) => {
const routerMap = {
home: "/",
history: "/history",
dashboard: "/dashboard",
streamers: "/streamers",
"upload-manager": "/upload-manager",
};
if(!routerMap[props.itemKey]) {
return itemElement;
}
return (
<Link
style={{ textDecoration: "none", fontWeight: "600 !important" }}
href={routerMap[props.itemKey]}
>
{itemElement}
</Link>
);
// return itemElement;
}, []);
let initOpenKeys = [];
console.log("slice(1)", router.pathname.slice(1));
if (router.pathname.slice(1) === 'streamers' || router.pathname.slice(1) === 'history') {
initOpenKeys = ['manager'];
}
const [openKeys, setOpenKeys] = useState(initOpenKeys);
const [selectedKeys, setSelectedKeys] = useState([router.pathname.slice(1)]);
const [isCollapsed, setIsCollapsed] = useState(false);
const items = useMemo(() =>[
{itemKey: 'manager', text: '录播管理',
items: [{itemKey: 'streamers', text: '直播管理'}, {itemKey: 'history', text: '历史记录'}],
icon: <div style={{
backgroundColor: '#5ac262ff',
borderRadius: 'var(--semi-border-radius-medium)',
color: 'var(--semi-color-bg-0)',
display: 'flex',
// justifyContent: 'center',
padding: '4px'
}}><IconVideoListStroked size='small'/></div>},
{itemKey: 'upload-manager', text: '投稿管理', icon: <div style={{
backgroundColor: '#885bd2ff',
borderRadius: 'var(--semi-border-radius-medium)',
color: 'var(--semi-color-bg-0)',
display: 'flex',
padding: '4px'
}}><IconCloudStroked size='small' /></div>},
// {itemKey: 'Job', text: '投稿管理', icon: <IconStar/>},
// {
// text: '任务平台',
// icon: <IconSetting/>,
// itemKey: 'Job',
// items: [{itemKey: 'About', text: '任务管理'}, {itemKey: 'Dashboard', text: '用户任务查询'}],
// },
].map(value => {
value.text = <div style={{
color: selectedKeys.some(key => value.itemKey === key) || (selectedKeys.some(key=> openKeys.some(o=> isSub(key, o))) && openKeys.some(key => value.itemKey === key)) ? 'var(--semi-color-text-0)' : 'var(--semi-color-text-2)',
fontWeight: 600
}}>{value.text}</div>
return value;
}), [openKeys, selectedKeys]);
// const [navStyle, setNavStyle] = useState({ height: '100%' });
const onSelect = data => {
setSelectedKeys([...data.selectedKeys]);
};
const onOpenChange = data => {
console.log('trigger onOpenChange: ', data);
setOpenKeys([...data.openKeys]);
};
let navStyle = isCollapsed ? { height: '100%', overflow: 'visible' } : { height: '100%' };
const onCollapseChange = useCallback( () => {
setIsCollapsed(!isCollapsed);
}, [isCollapsed]);
const [mode, setMode] = useState('light');
return (
<>
<SeLayout className="components-layout-demo semi-light-scrollbar">
<Sider>
<Nav
style={navStyle}
// toggleIconPosition={'left'}
// defaultOpenKeys={['job']}
openKeys={openKeys}
selectedKeys={selectedKeys}
isCollapsed={isCollapsed}
// bodyStyle={{height: '100%'}}
renderWrapper={renderWrapper}
items={items}
// onCollapseChange={onCollapseChange}
onOpenChange={onOpenChange}
onSelect={onSelect}
// header={{
// logo: <IconSemiLogo style={{height: '36px', fontSize: 36}}/>,
// text: 'BILIUP'
// }}
// footer={{
// collapseButton: true,
// }}
>
<Nav.Header
logo={<IconSemiLogo style={{height: '36px', fontSize: 36}}/>}
style={{justifyContent: 'flex-start'}}
text='BILIUP'
>
<div style={{flexGrow: 1, display: 'flex', flexDirection: 'row-reverse', alignSelf: 'flex-end'}}>
<Button
onClick={onCollapseChange} type="tertiary"
className={styles.shadow} theme='borderless'
icon={isCollapsed
? <IconDoubleChevronRight /> : <IconDoubleChevronLeft />}
/>
</div>
</Nav.Header>
{footer(mode, setMode)}
</Nav>
</Sider>
<SeLayout style={{height: '100vh'}}>
{children}
</SeLayout>
</SeLayout>
</>
)
}
function footer(mode, setMode) {
const switchMode = () => {
const body = document.body;
if (body.hasAttribute('theme-mode')) {
body.removeAttribute('theme-mode');
setMode('light');
} else {
body.setAttribute('theme-mode', 'dark');
setMode('dark');
}
};
return (
<Nav.Footer collapseButton={true} >
<Button
onClick={switchMode}
theme="borderless"
icon=
{mode === 'light'
? <IconMoon size="large"/>
: <IconSun size="large" />
}
style={{
color: 'var(--semi-color-text-2)',
// marginRight: '12px',
}}/>
</Nav.Footer>);
}
function isSub(key1, key2) {
const routerMap = {
manager: ["streamers", "history"],
};
return routerMap[key2]?.includes(key1);
}
+1 -1
View File
@@ -2,7 +2,7 @@ import logging
import platform
import sys
__version__ = "0.4.32"
__version__ = "0.4.33"
LOG_CONF = {
'version': 1,
-3
View File
@@ -131,9 +131,6 @@ class UploadBase:
event_manager.context['upload_filename'].extend(upload_filename_list)
lock.release()
file_list = self.upload(file_list)
if db.delete_stream_info_by_date(self.principal, self.data.get('date')) == 0:
# 如果按开播时间删除失败,则尝试按照 streamer 删除
db.delete_stream_info(self.principal)
return file_list
finally:
with NamedLock('upload_filename'):
+16 -1
View File
@@ -1,3 +1,4 @@
import datetime
import json
import os
import pathlib
@@ -13,7 +14,7 @@ import stream_gears
import biliup.common.reload
from biliup.config import config
from biliup.plugins.bili_webup import BiliBili, Data
from ..database.models import UploadStreamers, LiveStreamers, Configuration
from ..database.models import UploadStreamers, LiveStreamers, Configuration, StreamerInfo, FileList
from ..database.db import DB as db
BiliBili = BiliBili(Data())
@@ -173,6 +174,20 @@ async def streamers(request):
i += 1
return web.json_response(file_list)
@routes.get('/v1/streamer-info')
async def streamers(request):
res = []
for s_info in StreamerInfo.select():
streamer_info = model_to_dict(s_info)
streamer_info['files'] = []
for file in s_info.file_list:
tmp = model_to_dict(file)
del tmp['streamer_info']
streamer_info['files'].append(tmp)
streamer_info['date'] = int(streamer_info['date'].timestamp())
res.append(streamer_info)
return web.json_response(res)
@routes.get('/v1/streamers')
async def streamers(request):