First ui version for pip

This commit is contained in:
luckycat committed 2022-04-06 13:04:38 +08:00
1 parent 361e4adcb4
commit a1bc8200de
15 files changed
+312 -77

No files matched your search

+3
View File
@@ -9,6 +9,7 @@ old/
venv./
debug.py
config.yaml
!biliup/public/config.yaml
chromedriver.*
/configlog.ini
ds_update.log*
@@ -25,3 +26,5 @@ build/
bili.cookie.json
archive.txt
/node_modules
watch_process.pid
package-lock.json
+18 -11
View File
@@ -3,6 +3,7 @@ from http import cookies
from http.client import OK
import json
from multiprocessing.sharedctypes import Value
import os
from aiohttp import streamer
@@ -65,31 +66,37 @@ async def main(args):
return web.json_response(config.data['streamers'])
async def set_streamer_config(request):
post_data =await request.json()
for i,j in post_data['streamers'].items():
if i not in config.data['streamers']:
config.data['streamers'][i]={}
for key,Value in j.items():
config.data['streamers'][i][key]=Value
for i in config.data['streamers']:
if i not in post_data['streamers']:
del config.data['streamers'][i]
config.data['streamers']=post_data['streamers']
# for i,j in post_data['streamers'].items():
# if i not in config.data['streamers']:
# config.data['streamers'][i]={}
# for key,Value in j.items():
# config.data['streamers'][i][key]=Value
# for i in config.data['streamers']:
# if i not in post_data['streamers']:
# del config.data['streamers'][i]
print("sucess")
return web.json_response({"status":200},status=200)
async def save_config(reequest):
config.save()
return web.json_response({"status":200},status=200)
async def root_handler(request):
return web.HTTPFound('/index.html')
app = web.Application()
web_dir = os.path.dirname(__file__)
public_dir=(os.path.join(web_dir, 'public'))
build_dir =(os.path.join(public_dir, 'build'))
app.add_routes([web.get('/url-status', url_status)])
app.add_routes([web.get('/api/basic',get_basic_config)])
app.add_routes([web.post('/api/setbasic',set_basic_config)])
app.add_routes([web.get('/api/getconfig',get_streamer_config)])
app.add_routes([web.post('/api/setconfig',set_streamer_config)])
app.add_routes([web.get('/api/save',save_config)])
app.add_routes([web.static('/public','./public',show_index=False)])
app.add_routes([web.static('/build','./public/build',show_index=False)])
app.add_routes([web.get('/', root_handler)])
app.add_routes([web.static('/',public_dir,show_index=False)])
app.add_routes([web.static('/build',build_dir,show_index=False)])
cors = aiohttp_cors.setup(app, defaults={
"*": aiohttp_cors.ResourceOptions(
allow_credentials=True,
+4 -1
View File
@@ -72,7 +72,10 @@ def arg_parser():
parser_restart.set_defaults(func=daemon.restart)
parser.set_defaults(func=lambda: asyncio.run(main(args)))
args = parser.parse_args()
config.load(args.config)
if(args.http):
config.create_without_config_input(args.config)
else:
config.load(args.config)
LOG_CONF.update(config.get('LOGGING', {}))
if args.verbose:
LOG_CONF['loggers']['biliup']['level'] = args.verbose
+16
View File
@@ -1,4 +1,8 @@
from collections import UserDict
import os
import shutil
import biliup
from .decorators import Plugin
@@ -9,6 +13,18 @@ class Config(UserDict):
file = open('config.yaml', encoding='utf-8')
with file as stream:
self.data = yaml.load(stream, Loader=yaml.FullLoader)
def create_without_config_input(self, file):
import yaml
if file is None:
try:
file = open('config.yaml', encoding='utf-8')
except FileNotFoundError:
biliup_dir = os.path.dirname(biliup.__file__)
config_data = os.path.join(biliup_dir,"public/","config.yaml")
shutil.copy(config_data, os.getcwd())
file = open('config.yaml', encoding='utf-8')
with file as stream:
self.data = yaml.load(stream, Loader=yaml.FullLoader)
def save(self):
import yaml
old_file = open('config.yaml',encoding='utf-8')
+108
View File
@@ -0,0 +1,108 @@
user: # 在填了cookies的情况下优先使用cookies上传,如需使用用户名密码上传请注释掉cookies
cookies:
SESSDATA: your SESSDATA
bili_jct: your bili_jct
DedeUserID__ckMd5: your ckMd5
DedeUserID: your DedeUserID
access_token: your access_key
# account:
# username: your usrname
# password: your password
# app_key: bca7e84c2d947ac6 # 若账号密码方式无法登录可尝试更改此值
# appsec: 60698ba2f68e01ce44738920a0ffe768
# 选择全局默认上传插件,Noop为不上传,但会执行后处理
#uploader: Noop
# b站上传线路选择,默认为自动模式,目前可手动切换为bda2, kodo, ws, qn, cos, cos-internal(支持腾讯云内网免流+提速)
lines: AUTO
# b站提交接口,默认自动选择,可选web,client
submit_api: client
# 单文件并发上传数,未达到带宽上限时增大此值可提高上传速度
threads: 3
# 录像单文件大小限制,单位Byte,超过此大小分段下载
file_size: 2621440000
# 录像单文件时间限制,格式'00:00:00'(时分秒),超过此大小分段下载,如需使用大小分段请注释此字段
#segment_time: '00:50:00'
filtering_threshold: 20 # 小于此大小的视频文件将会被过滤删除,单位MB
# 如遇到斗鱼录制卡顿可以尝试切换线路,tct-h5(备用线路5),ali-h5(备用线路6),akm-h5(主线路1)
#douyucdn: tct-h5
# 如遇到虎牙录制卡顿可以尝试切换线路,AL(阿里),BD(百度),TX(腾讯)
#huyacdn: AL
# 如遇到哔哩哔哩录制跳帧可以尝试修改platform值,web(flv),h5(m3u8)
#biliplatform: web
# 如需要录制抖音请在此填入cookie需要__ac_nonce与__ac_signature的值
#douyin_cookie: '__ac_nonce=123456; __ac_signature=123456;'
# Netscape 格式的 Cookies 文本路径
#youtube_cookie: 'cookiejar.txt'
streamers:
星际2Stats拔本神族天梯第一视角: # 最小配置示例
url:
- https://www.twitch.tv/kimdaeyeob3
星际2INnoVation吕布卫星人族天梯第一视角: # 完整可选配置示例
url:
- https://www.twitch.tv/innovation_s2
- https://www.panda.tv/1160340
title: "{title}第一视角%Y-%m-%d" # 自定义标题的时间格式, {title}代表直播间标题
tid: 171 # 投稿分区码,171为电子竞技分区
copyright: 2 # 1为自制
cover_path: /cover/up.jpg
description: "视频简介: {title} %Y-%m-%d %H:%M:%S" # 支持strftime, {title}占位符
dynamic: '#空间动态#'
dtime: 14400 # 设置延时发布时间,距离提交大于2小时,格式为时间戳
# 覆盖全局默认上传插件,Noop为不上传,但会执行后处理
uploader: bili_web
postprocessor: # 上传完成后,将按自定义顺序执行自定义操作
- run: echo hello! # 执行任意命令,等同于在shell中运行,视频文件路径作为标准输入传入
- mv: backup/ # 移动文件到backup目录下
# - rm # 删除文件,为默认操作
tags:
- 星际争霸2
- 电子竞技
format: mp4 # 视频保存格式
opt_args: # ffmpeg参数
- '-ss' # 跳过开始的16秒
- '00:00:16'
# 检测间隔时间,单位:秒
event_loop_interval: 40
# 相同平台检测间隔,单位:秒。不同平台的链接是并发的,不受此参数影响
checker_sleep: 15
# 线程池1大小,负责download事件
pool1_size: 3
# 线程池2大小,处理除download事件外所有其他事件
pool2_size: 3
# 检测源码文件变化间隔,单位:秒,检测源码到变化后,程序会在空闲时自动重启
check_sourcecode: 15
# 日志输出配置
LOGGING:
formatters:
verbose:
format: '%(asctime)s %(filename)s[line:%(lineno)d](Pid:%(process)d Tname:%(threadName)s) %(levelname)s %(message)s'
datefmt: '%Y-%m-%d %H:%M:%S'
simple:
format: '%(filename)s%(lineno)d[%(levelname)s]Tname:%(threadName)s %(message)s'
handlers:
console:
level: DEBUG
class: logging.StreamHandler
formatter: simple
stream: ext://sys.stdout
file:
level: DEBUG
class: biliup.common.log.SafeRotatingFileHandler
when: W0
interval: 1
backupCount: 1
filename: ds_update.log
formatter: verbose
root:
handlers: [ console ]
level: INFO
loggers:
biliup:
handlers: [ file ]
level: INFO
# 默认通过网页接口上传,可选通过操作chrome上传,此时需要填写chromedriver路径
#chromedriver_path: /usr/local/bin/chromedriver
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

-31
View File
@@ -1,31 +0,0 @@
/* width */
::-webkit-scrollbar {
width: 0.5rem;
/*height: 5px;*/
}
/* Track */
::-webkit-scrollbar-track {
border-radius: 100vh;
background: #ffffff00;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #cbd5e0;
border-radius: 100vh;
border: 1px solid #edf2f7;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #a0aec0;
}
body {
overflow-x: hidden;
}
.tippy-content{
padding: 0 !important;
}
-17
View File
@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

+1
View File
@@ -8,3 +8,4 @@ PyYAML>=4.2b1
streamlink>=0.14.2
ykdl>=1.8.0
rsa>=4.6
aiohttp_cors
+1 -1
View File
@@ -37,7 +37,7 @@ export default {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
file: 'biliup/public/build/bundle.js'
},
plugins: [
svelte({
+1 -1
View File
@@ -25,7 +25,7 @@ install_requires =
rsa >= 4.6
[options.package_data]
biliup = common/*.ini,public/*
biliup = common/*.ini,public/*,public/build/*
[options.packages.find]
include = biliup*
+3 -1
View File
@@ -1,2 +1,4 @@
import setuptools
setuptools.setup()
setuptools.setup(
package_dir={'build':'biliup/'}
)
+46 -11
View File
@@ -63,6 +63,7 @@
// console.log()
let tags = selectedTemplate?.tags ? selectedTemplate?.tags : [];
let urls = selectedTemplate?.url ? selectedTemplate?.url : [];
// $: tags = selectedTemplate?.tag.split(',');
let parent = '请选择';
@@ -98,7 +99,7 @@
}
let tempTag;
let tempUrl;
function handleKeypress() {
@@ -109,16 +110,32 @@
return;
}
tags = [...tags, tempTag];
selectedTemplate.tag = tags.join(',');
selectedTemplate.tags = tags;
tempTag = null;
return false;
}
function urlhandleKeypress(){
console.log(urls);
if(urls.includes(tempUrl)){
createPop("已有相同链接");
tempUrl = null;
return;
}
urls = [...urls, tempUrl];
selectedTemplate.url = urls;
tempUrl=null;
return false;
}
function removeTag(tag) {
tags = tags.filter(t => t !== tag);
selectedTemplate.tag = tags.join(',');
selectedTemplate.tags = tags;
console.log(tag);
}
function removeUrl(url) {
urls = urls.filter(u => u !== url);
selectedTemplate.url = urls;
console.log(url);
}
function callback(detailTid, detailParent, detailChildren) {
@@ -181,13 +198,31 @@
placeholder="标题">
</div>
<div class="flex flex-col">
<label class="label">
<span class="text-sm font-bold text-gray-500 tracking-wide">直播间链接</span>
</label>
<input bind:value={selectedTemplate.url}
class="text-base p-2 border border-gray-300 rounded-lg focus:outline-none focus:border-indigo-500"
placeholder="www.douyu.com/3484">
<!-- <div class="flex flex-col">-->
<!-- <label class="label">-->
<!-- <span class="text-sm font-bold text-gray-500 tracking-wide">直播间链接</span>-->
<!-- </label>-->
<!-- <input bind:value={selectedTemplate.url}-->
<!-- class="text-base p-2 border border-gray-300 rounded-lg focus:outline-none focus:border-indigo-500"-->
<!-- placeholder="www.douyu.com/3484">-->
<!-- </div>-->
<div class="flex flex-wrap rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent">
{#each urls as url(url)}
<span animate:flip="{{duration: 300}}" class="flex ml-1 my-1.5 px-3 py-0.5 text-base rounded-full text-white bg-indigo-500 ">
{url}
<button on:click={(e)=>{removeUrl(url)}} class="bg-transparent hover">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor"
class="ml-2" viewBox="0 0 1792 1792">
<path d="M1490 1322q0 40-28 68l-136 136q-28 28-68 28t-68-28l-294-294-294 294q-28 28-68 28t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 294 294-294q28-28 68-28t68 28l136 136q28 28 28 68t-28 68l-294 294 294 294q28 28 28 68z">
</path>
</svg>
</button>
</span>
{/each}
<input bind:value={tempUrl} class="outline-none rounded-lg flex-1 appearance-none w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base " on:keypress={e=>e.key==='Enter' && urlhandleKeypress()}
placeholder="录制链接"
type="text"/>
</div>
+111 -3
View File
@@ -1,5 +1,9 @@
import { writable } from "svelte/store";
import { crossfade, fly } from "svelte/transition";
import {writable} from "svelte/store";
import {open} from "@tauri-apps/api/dialog";
import {sep} from "@tauri-apps/api/path";
import {invoke} from "@tauri-apps/api/tauri";
import {crossfade, fly} from "svelte/transition";
import {createPop} from "./common";
export const isLogin = writable(true);
@@ -24,7 +28,111 @@ export const currentTemplate = writable({
export const [send, receive] = crossfade({
duration: 800,
fallback: (node, params) => {
return fly(node, { x: 200, delay: 500 });
return fly(node, {x: 200, delay: 500});
},
});
export const fileselect = () => {
let properties = {
// defaultPath: 'C:\\',
multiple: true,
// directory: false,
filters: [{
extensions: ['mp4', 'flv', 'avi', 'wmv', 'mov', 'webm', 'mpeg4', 'ts', 'mpg', 'rm', 'rmvb', 'mkv', 'm4v'],
name: ""
}]
};
open(properties).then((pathStr) => {
console.log(pathStr);
if (!pathStr) return;
attach(pathStr);
});
};
export function attach(files) {
currentTemplate.update(temp => {
function findFile(file) {
return temp.selectedTemplate['files'].find((existingFile) => existingFile.id === file);
}
for (const file of files) {
if (findFile(file)) {
createPop('请上传非重复视频!');
continue;
}
let split = file.split(sep);
let filename = split[split.length - 1];
// temp['files'] = [...temp['files'], ...event.target.files];
temp.selectedTemplate['files'].push({
filename: file,
id: file,
title: filename.substring(0, filename.lastIndexOf(".")),
desc: '',
progress: 0,
speed: 0,
totalSize: 0,
complete: false,
process: false,
});
// let objectURL = URL.createObjectURL(file);
// console.log(objectURL);
}
const res = allComplete(temp.selectedTemplate['files'], temp.selectedTemplate);
console.log(res);
return temp;
});
}
function allComplete(files, temp) {
// console.log(temp);
for (const file of files) {
if (!file.complete && !file.process && temp.atomicInt < 1) {
temp.atomicInt++;
file.process = true;
upload(file, temp);
console.log(temp);
return false;
}
}
return true;
}
function upload(video, temp) {
// const files = [];
invoke('upload', {
video: video
}).then((res) => {
// temp.atomicInt--;
video.filename = res[0].filename;
video.speed = res[1];
video.complete = true;
video.progress = 100;
currentTemplate.update(t => {
t.selectedTemplate.files.forEach(file => {
if (file.id === video.id) {
file.filename = res[0].filename;
file.speed = res[1];
file.complete = true;
file.progress = 100;
}
})
return t;
});
console.log(`Message:`, res);
}).catch((e) => {
createPop(`${video.filename}: ${e}`, 5000);
console.log(e);
}).finally(() => {
temp.atomicInt--;
if (allComplete(temp['files'], temp)) {
console.log(temp.submitCallback);
if (temp.submitCallback) {
temp.submitCallback();
temp.submitCallback=null;
}
console.log("allComplete");
return;
}
})
}