Fix ui bug,add login page for biliup (#155)

* Add  Douyin Mainpage Url Support For Douyin Recorder

* Fix issues 119

* Delete Tid Table
This commit is contained in:
luckycat0426 authored and GitHub committed 2022-06-14 14:09:31 +08:00
1 parent 1521b8b1b6
commit f260a50582
10 files changed
+530 -2113

No files matched your search

+67 -2
View File
@@ -6,6 +6,7 @@ import math
import os
import sys
import time
import urllib.parse
from dataclasses import asdict, dataclass, field, InitVar
from json import JSONDecodeError
from os.path import splitext, basename
@@ -56,7 +57,7 @@ class BiliWeb(UploadBase):
video_part = bili.upload_file(file, self.lines, self.threads) # 上传视频
video_part['title'] = video_part['title'][:80]
video.append(video_part) # 添加已经上传的视频
video.title = self.data["format_title"][:80] #稿件标题限制80字
video.title = self.data["format_title"][:80] # 稿件标题限制80字
video.desc = self.desc
video.copyright = self.copyright
if self.copyright == 2:
@@ -95,6 +96,42 @@ class BiliBili:
self._auto_os = None
self.persistence_path = 'engine/bili.cookie'
def get_qrcode(self):
params = {
"appkey": "4409e2ce8ffd12b8",
"local_id": "0",
"ts": int(time.time()),
}
params["sign"] = hashlib.md5(
f"{urllib.parse.urlencode(params)}59b43e04ad6965f34319062b478f83dd".encode()).hexdigest()
response = self.__session.post("http://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code", data=params,
timeout=5)
r = response.json()
if r and r["code"] == 0:
return r
async def login_by_qrcode(self, value):
params = {
"appkey": "4409e2ce8ffd12b8",
"auth_code": value["data"]["auth_code"],
"local_id": "0",
"ts": int(time.time()),
}
params["sign"] = hashlib.md5(
f"{urllib.parse.urlencode(params)}59b43e04ad6965f34319062b478f83dd".encode()).hexdigest()
for i in range(0, 120):
await asyncio.sleep(1)
response = self.__session.post("http://passport.bilibili.com/x/passport-tv-login/qrcode/poll", data=params,
timeout=5)
r = response.json()
if r and r["code"] == 0:
return r
raise "Qrcode timeout"
def tid_archive(self,cookies):
requests.utils.add_dict_to_cookiejar(self.__session.cookies, cookies)
response = self.__session.get("https://member.bilibili.com/x/vupre/web/archive/pre")
return response.json()
def login(self, persistence_path, user):
self.persistence_path = persistence_path
if os.path.isfile(persistence_path):
@@ -131,6 +168,35 @@ class BiliBili:
'refresh_token': self.refresh_token
}, f)
def send_sms(self, phone_number, country_code ):
params = {
"actionKey": "appkey",
"appkey": "783bbb7264451d82",
"build": 6510400,
"channel": "bili",
"cid": country_code,
"device": "phone",
"mobi_app": "android",
"platform": "android",
"tel": phone_number,
"ts": int(time.time()),
}
sign = hashlib.md5(f"{urllib.parse.urlencode(params)}2653583c8873dea268ab9386918b1d65".encode()).hexdigest()
payload = f"{urllib.parse.urlencode(params)}&sign={sign}"
response = self.__session.post("https://passport.bilibili.com/x/passport-login/sms/send", data=payload,
timeout=5)
return response.json()
def login_by_sms(self, code, params):
params["code"] = code
params["sign"] = hashlib.md5(
f"{urllib.parse.urlencode(params)}59b43e04ad6965f34319062b478f83dd".encode()).hexdigest()
response = self.__session.post("https://passport.bilibili.com/x/passport-login/login/sms", data=params,
timeout=5)
r = response.json()
if r and r["code"] == 0:
return r
def login_by_password(self, username, password):
print('使用账号上传')
key_hash, pub_key = self.get_key()
@@ -175,7 +241,6 @@ class BiliBili:
requests.utils.add_dict_to_cookiejar(self.__session.cookies, cookie)
if 'bili_jct' in cookie:
self.__bili_jct = cookie["bili_jct"]
data = self.__session.get("https://api.bilibili.com/x/web-interface/nav", timeout=5).json()
if data["code"] != 0:
raise Exception(data)
+58 -7
View File
@@ -2,6 +2,9 @@ from aiohttp import web
from .aiohttp_basicauth_middleware import basic_auth_middleware
from biliup.config import config
from biliup.plugins.bili_webup import BiliBili, Data
BiliBili = BiliBili(Data())
async def get_basic_config(request):
@@ -25,11 +28,14 @@ async def set_basic_config(request):
if config.data['lines'] == 'cos':
config.data['lines'] = 'cos-internal'
config.data['threads'] = post_data['limit']
config.data['user']['cookies']['SESSDATA'] = post_data['user']['SESSDATA']
config.data['user']['cookies']['bili_jct'] = post_data['user']['bili_jct']
config.data['user']['cookies']['DedeUserID__ckMd5'] = post_data['user']['DedeUserID__ckMd5']
config.data['user']['cookies']['DedeUserID'] = post_data['user']['DedeUserID']
config.data['user']['access_token'] = post_data['user']['access_token']
cookies ={
"SESSDATA": str(post_data['user']['SESSDATA']),
"bili_jct": str(post_data['user']['bili_jct']),
"DedeUserID__ckMd5": str(post_data['user']['DedeUserID__ckMd5']),
"DedeUserID": str(post_data['user']['DedeUserID']),
}
config.data['user']['cookies'] = cookies
config.data['user']['access_token'] = str(post_data['user']['access_token'])
return web.json_response({"status": 200})
@@ -62,10 +68,49 @@ async def root_handler(request):
return web.HTTPFound('/index.html')
async def service(args, event_manager):
async def cookie_login(request):
cookie = config.data['user']['cookies']
try:
BiliBili.login_by_cookies(cookie)
except Exception as e:
print(e)
return web.HTTPBadRequest(text="login failed")
return web.json_response({"status": 200})
async def sms_login(request):
pass
async def sms_send(request):
post_data = await request.json()
pass
async def qrcode_get(request):
r = BiliBili.get_qrcode()
return web.json_response(r)
async def qrcode_login(request):
post_data = await request.json()
try:
r = await BiliBili.login_by_qrcode(post_data)
except:
return web.HTTPBadRequest(text="timeout for qrcode validate")
for cookie in r['data']['cookie_info']['cookies']:
config.data['user']['cookies'][cookie['name']] = cookie['value']
config.data['user']['access_token'] = r['data']['token_info']['access_token']
return web.json_response(r)
async def pre_archive(request):
cookies = config.data['user']['cookies']
return web.json_response(BiliBili.tid_archive(cookies))
async def service(args, event_manager):
async def url_status(request):
return web.json_response(event_manager.context['KernelFunc'].get_url_status())
app = web.Application()
try:
from importlib.resources import files
@@ -77,7 +122,13 @@ async def service(args, event_manager):
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/login_by_cookie', cookie_login)])
app.add_routes([web.get('/api/login_by_sms', sms_login)])
app.add_routes([web.post('/api/send_sms', sms_send)])
app.add_routes([web.get('/api/save', save_config)])
app.add_routes([web.get('/api/get_qrcode', qrcode_get)])
app.add_routes([web.post('/api/login_by_qrcode', qrcode_login)])
app.add_routes([web.get('/api/archive_pre', pre_archive)])
app.add_routes([web.get('/', root_handler)])
if args.static_dir:
app.add_routes([web.static('/', args.static_dir, show_index=False)])
@@ -91,4 +142,4 @@ async def service(args, event_manager):
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, host=args.host, port=args.port)
return runner, site
return runner, site
+3 -2
View File
@@ -17,6 +17,7 @@
"@tsconfig/svelte": "^2.0.0",
"autoprefixer": "^10.4.2",
"daisyui": "^2.6.4",
"ncp": "^2.0.0",
"postcss": "^8.4.5",
"postcss-import": "^14.0.2",
"postcss-load-config": "^3.1.0",
@@ -31,11 +32,11 @@
"svelte-preprocess": "^4.9.8",
"tailwindcss": "^3.0.16",
"tslib": "^2.0.0",
"typescript": "^4.0.0",
"ncp": "^2.0.0"
"typescript": "^4.0.0"
},
"dependencies": {
"sirv-cli": "^1.0.0",
"svelte-qrcode": "^1.0.0",
"tippy.js": "^6.3.7"
}
}
+25
View File
@@ -1,12 +1,37 @@
<script lang="ts">
import Home from './Home.svelte';
import Modal from "./Modal.svelte";
import {isLogin} from './store.ts';
import {notifyHistory} from "./common";
import Login from "./Login.svelte";
fetch('/api/login_by_cookie')
.then((res) => {
if (res.ok) {
isLogin.set(true);
console.log(`Message: ${res}`);
} else {
$notifyHistory = [...$notifyHistory, {
type: 'Error',
msg: '校验Cookies失败',
date: new Date(),
duration: 3000
}];
isLogin.set(false);
}
}).catch((e) => $notifyHistory = [...$notifyHistory, {
type: 'Error',
msg: e,
date: new Date(),
}]);
</script>
<main class="bg-gray-100" on:dragenter|preventDefault on:dragleave|preventDefault on:dragover|preventDefault
on:drop|preventDefault>
{#if $isLogin}
<Home/>
{:else}
<Login/>
{/if}
<div class="fixed space-y-2.5 top-0 right-0 w-1/2" id="alerts">
</div>
<ul class="menu bg-base-100 rounded-box fixed bottom-16 right-3 w-max drop-shadow">
+257
View File
@@ -0,0 +1,257 @@
<script lang="ts">
import {isLogin} from './store.js';
import {fade, scale} from 'svelte/transition';
import {createPop, notifyHistory} from "./common";
import QrCode from 'svelte-qrcode';
let rememberMe: boolean = false;
let username;
let password;
let loginMethod = "password";
let countryCode = 86;
let telephone: number = null;
let verificationCode = null;
let qrcode;
let ret;
let throttle = false;
let maxtime = 60;
function login_by_sms() {
fetch('/api/login_by_sms', {
method: 'POST'
})
.then((res) => {
fetch('login_by_cookie')
.then((res) => {
isLogin.set(true);
console.log(`Message: ${res}`)
}).catch((e) => createPop(e, 5000))
}).catch((e) => createPop(e, 5000))
}
function sendSms() {
throttle = true;
function CountDown() {
if (maxtime >= 0) {
--maxtime;
} else {
throttle = false;
clearInterval(timer);
maxtime = 60;
}
}
let timer = setInterval(CountDown, 1000);
fetch('/api/send_sms', {
method: 'POST',
body: JSON.stringify({
bodycountrycode: countryCode,
phone: telephone
})
})
.then((res) => ret = res).catch((e) => createPop(e, 5000));
}
function loginByQrcode() {
loginMethod = "qrcode";
fetch('/api/get_qrcode')
.then(ret => ret.json()).then((res) => {
qrcode = res["data"]["url"];
fetch('/api/login_by_qrcode', {
method: 'POST',
body: JSON.stringify(res),
}).then((res) => {
if (res.ok) {
fetch('/api/login_by_cookie')
.then((res) => {
isLogin.set(true)
console.log(`Message: ${res}`)
}).catch((e) => createPop(e, 5000));
} else {
createPop(res.body, 5000);
}
}).catch((e) => {
createPop(e, 5000);
console.log(e);
})
}).catch((e) => {
createPop(e, 5000);
console.log(e);
}
)
}
async function browser() {
let ret = await fetch('/api/get_qrcode');
let res = await ret.json();
await open(res["data"]["url"],'','noreferrer,popup');
await fetch('/api/login_by_qrcode', {
method: 'POST',
body: JSON.stringify(res),
})
await fetch('/api/login_by_cookie')
.then((res) => {
if (res.ok) {
isLogin.set(true);
console.log(`Message: ${res}`);
} else {
$notifyHistory = [...$notifyHistory, {
type: 'Error',
msg: '校验Cookies失败',
date: new Date(),
duration: 3000
}];
isLogin.set(false);
}
})
console.log(`Message: ${res}`);
}
function login() {
console.log(rememberMe);
invoke('login', {username: username, password: password, rememberMe: rememberMe})
.then((res) => {
isLogin.set(true);
console.log(`Message: ${res}`)
}).catch((e) => {
createPop(e, 5000);
console.log(e);
// e = JSON.parse(e);
// {"code":0,"data":{"cookie_info":null,"message":
// "本次登录环境存在风险, 需使用手机号进行验证或绑定",
// "sso":null,"status":2,
// "token_info":null,
// "url":"https://passport.bilibili.com/account/mobile/security/managephone/phone/verify?tmp_token=&requestId=&source=risk"},
// "message":"0","ttl":1}
// const webview = new WebviewWindow('theUniqueLabel', {
// url: e.data.url
// })
// createPop(JSON.stringify(e), 5000);
})
}
</script>
<div class="abs min-h-screen flex flex-col sm:justify-center items-center bg-white " transition:fade>
<div class="relative sm:max-w-sm w-full" transition:scale>
<div class="card bg-blue-400 shadow-lg w-full h-full rounded-3xl absolute transform -rotate-6"></div>
<div class="card bg-red-400 shadow-lg w-full h-full rounded-3xl absolute transform rotate-6"></div>
<div class="relative w-full rounded-3xl px-10 py-5 bg-zinc-50 shadow-md">
{#if loginMethod === "password"}
<div class="indicator w-full -mx-10">
<button class="indicator-item link flex text-sm" on:click={browser}>浏览器登录
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
</svg>
</button>
</div>
<form>
<label class="block text-sm text-gray-800">用户名</label>
<input bind:value={username}
class="block w-full px-4 py-2 mt-2 text-gray-700 bg-white border rounded-md focus:border-blue-500 focus:outline-none focus:ring"
type="text">
<div class="mt-4">
<div class="flex items-center justify-between">
<label class="block text-sm text-gray-800" for="password">密码</label>
</div>
<input bind:value={password}
class="block w-full px-4 py-2 mt-2 text-gray-700 bg-white border rounded-md focus:border-blue-500 focus:outline-none focus:ring"
type="password">
</div>
<label class="flex items-center mt-4">
<input bind:checked={rememberMe} class="form-checkbox" type="checkbox"/>
<span class="block ml-2 text-xs font-medium text-gray-700 cursor-pointer">Remember me</span>
</label>
<div class="mt-6">
<button class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-gray-700 rounded-md hover:bg-gray-600 focus:outline-none focus:bg-gray-600"
on:click|preventDefault={login}>
登录
</button>
</div>
</form>
{:else if loginMethod === "qrcode"}
<div class="flex items-center justify-center">
<QrCode background="#fafafa" value={qrcode}/>
</div>
{:else if loginMethod === "sms"}
<div class="form-control">
<label class="label">
<span class="label-text">国家代码+手机号</span>
</label>
<div class="flex">
<input type="text" placeholder="国家代码" bind:value={countryCode}
class="input input-bordered w-[5.75rem]">
<input type="text" placeholder="phone numbers" bind:value={telephone} class="input ml-2 w-full">
</div>
<label class="label">
<span class="label-text">验证码</span>
</label>
<div class="relative">
<input type="text" placeholder="verification code" bind:value={verificationCode}
class="w-full pr-16 input input-primary">
<button on:click={sendSms} class:loading={throttle} disabled={throttle}
class="absolute top-0 right-0 rounded-l-none btn btn-primary">
{#if !throttle}
发送验证码
{:else}
已发送(
<span class="countdown">
<span style="--value:{maxtime};"></span>
</span>)
{/if}
</button>
</div>
</div>
<button class="btn btn-block mt-2.5" on:click={login_by_sms}>登录</button>
{/if}
<div class="flex items-center justify-between mt-4">
<span class="w-1/5 border-b dark:border-gray-600 lg:w-1/5"></span>
<a on:click={() => loginMethod='password'} href="#"
class="text-xs text-center text-gray-500 uppercase dark:text-gray-400 hover:underline">若登录失败,尝试其他登录方式</a>
<span class="w-1/5 border-b dark:border-gray-400 lg:w-1/5"></span>
</div>
<div class="flex items-center mt-6 -mx-2">
<button type="button" on:click={() => loginMethod = "sms"}
class="flex items-center justify-center w-full px-6 py-2 mx-2 text-sm font-medium text-white transition-colors duration-200 transform bg-blue-500 rounded-md hover:bg-blue-400 focus:bg-blue-400 focus:outline-none">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"/>
</svg>
<span class="hidden mx-2 sm:inline">短信登录</span>
</button>
<a href="#" on:click={loginByQrcode}
class="flex items-center justify-center px-6 py-2 mx-2 w-full text-sm font-medium text-gray-500 transition-colors duration-200 transform bg-gray-300 rounded-md hover:bg-gray-200">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"/>
</svg>
<!-- <svg class="w-5 h-5 fill-current" viewBox="0 0 24 24">-->
<!-- <path-->
<!-- d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z">-->
<!-- </path>-->
<!-- </svg>-->
<span class="hidden mx-2 sm:inline">扫码登录</span>
</a>
</div>
</div>
</div>
</div>
<style>
.abs {
/*overflow-y: overlay;*/
margin-right: calc(100% - 100vw);
}
</style>
+8 -3
View File
@@ -2,8 +2,7 @@
</script>
<script>
import {createEventDispatcher} from 'svelte';
import { partition} from "./common";
import {tid_table} from "./tid";
import { partition,createPop} from "./common";
const dispatch = createEventDispatcher();
export let currentChildren;
@@ -15,7 +14,13 @@
let currentTypelist = [];
if ($partition === null) {
$partition = [];
$partition = tid_table.typelist;
fetch("/api/archive_pre").then(res => res.json()).then(data => {
if(data.code!==0){
createPop("加载分区表失败");
}
$partition = data['data']['typelist'];
console.log("加载分区表", data);
});
}
+3 -2
View File
@@ -17,7 +17,7 @@
url: '',
copyright: 1,
source: "",
tid: 0,
tid: 171,
description: "",
tags: '',
dynamic: "",
@@ -25,7 +25,6 @@
desc_format_id: 0,
atomicInt: 0
};
// $currentTemplate = $template[name];
let res;
res = await fetch('/api/getconfig')
let res_json = await res.json();
@@ -34,6 +33,7 @@
method: "POST",
body:JSON.stringify(res_json)
})
select(name);
}
@@ -60,6 +60,7 @@
let ret = await fetch('/api/basic');
let ret_json = await ret.json();
console.log(ret_json);
ret_json.line = ret_json.line.toLowerCase();
if (ret_json.line === null) {
line = 'auto';
} else {
+108 -50
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import {receive, template} from './store';
import {currentTemplate, receive, template} from './store';
import {archivePre, createPop, partition} from "./common";
import {flip} from 'svelte/animate';
@@ -7,10 +7,12 @@
export let selected;
export let selectedTemplate;
let oldSelected = selected;
let uploaders = ["bili_web", "Noop"];
// let title: string = ;
let nocopyright: boolean;
$ : nocopyright = selectedTemplate?.copyright === 2;
let noReprint = true;
function handleClick(e) {
selectedTemplate.copyright = e.target.checked ? 2 : 1;
}
@@ -25,10 +27,10 @@
selectedTemplate.changed = true;
$template[selected] = selectedTemplate;
console.log($template);
let data={
let data = {
"streamers": $template,
}
fetch('/api/setconfig',{
fetch('/api/setconfig', {
method: 'POST',
body: JSON.stringify(data),
headers: {
@@ -40,14 +42,30 @@
}
async function del() {
let len = Object.keys($template).length;
const keys = Object.keys($template);
const index = keys.indexOf(selected);
if (len==1){
createPop("已经是最后一个模板无法删除");
return;
}
delete $template[selected];
if (len > 1) {
selected = keys[index + 1] || keys[index - 1];
$currentTemplate.selectedTemplate = $template[selected];
$currentTemplate.current = selected;
} else {
selected = '';
$currentTemplate.selectedTemplate = null;
$currentTemplate.current = '';
}
$template = $template;
let data = {
"streamers":$template
"streamers": $template
}
console.log($template);
try {
await fetch('/api/setconfig',{
await fetch('/api/setconfig', {
method: 'POST',
body: JSON.stringify(data),
headers: {
@@ -59,6 +77,7 @@
console.log(e);
createPop(e, 5000);
}
}
// console.log()
@@ -109,28 +128,36 @@
tempTag = null;
return;
}
if(tags.length > 10) {
createPop("标签数量超过10个,无法添加");
tempTag = null;
return;
}
tags = [...tags, tempTag];
selectedTemplate.tags = tags;
tempTag = null;
return false;
}
function urlhandleKeypress(){
function urlhandleKeypress() {
console.log(urls);
if(urls.includes(tempUrl)){
if (urls.includes(tempUrl)) {
createPop("已有相同链接");
tempUrl = null;
return;
}
urls = [...urls, tempUrl];
selectedTemplate.url = urls;
tempUrl=null;
tempUrl = null;
return false;
}
function removeTag(tag) {
tags = tags.filter(t => t !== tag);
selectedTemplate.tags = tags;
console.log(tag);
}
function removeUrl(url) {
urls = urls.filter(u => u !== url);
selectedTemplate.url = urls;
@@ -143,6 +170,7 @@
parent = detailParent;
children = detailChildren;
}
let dtime;
let isDtime = false;
let date;
@@ -156,22 +184,24 @@
in:receive={{key: selected}}>
<div class="space-y-3">
<div class="flex flex-row-reverse">
<button class="ml-2 py-2 px-2 flex justify-center items-center bg-red-600 hover:bg-red-700 focus:ring-red-500 focus:ring-offset-red-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 w-8 h-8 rounded-lg " on:click|preventDefault={del}
<button class="ml-2 py-2 px-2 flex justify-center items-center bg-red-600 hover:bg-red-700 focus:ring-red-500 focus:ring-offset-red-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 w-8 h-8 rounded-lg "
on:click|preventDefault={del}
type="button">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" stroke-linecap="round" stroke-linejoin="round"
<path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
stroke-linecap="round" stroke-linejoin="round"
stroke-width="2"/>
</svg>
</button>
<!-- <button class="py-2 px-2 flex justify-center items-center bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 w-8 h-8 rounded-lg " on:click|preventDefault={save}-->
<!-- type="button">-->
<!-- <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"-->
<!-- xmlns="http://www.w3.org/2000/svg">-->
<!-- <path d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" stroke-linecap="round" stroke-linejoin="round"-->
<!-- stroke-width="2"/>-->
<!-- </svg>-->
<!-- </button>-->
<!-- <button class="py-2 px-2 flex justify-center items-center bg-blue-600 hover:bg-blue-700 focus:ring-blue-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 w-8 h-8 rounded-lg " on:click|preventDefault={save}-->
<!-- type="button">-->
<!-- <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"-->
<!-- xmlns="http://www.w3.org/2000/svg">-->
<!-- <path d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" stroke-linecap="round" stroke-linejoin="round"-->
<!-- stroke-width="2"/>-->
<!-- </svg>-->
<!-- </button>-->
</div>
<div class="flex flex-col">
<label class="text-sm font-bold text-gray-500 tracking-wide mb-2">
@@ -198,17 +228,18 @@
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>-->
<!-- <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 ">
<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"
@@ -220,28 +251,28 @@
</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()}
<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>
<div class="mb-3 flex justify-between items-center">
<!-- <div>-->
<!-- <div class="relative inline-block w-10 mr-2 align-middle select-none">-->
<!-- bind:checked={nocopyright}-->
<input checked={nocopyright} class="toggle" id="Orange"
name="toggle" on:change={(event) => handleClick(event)}
type="checkbox"/>
<!-- <label class="block overflow-hidden h-6 rounded-full bg-gray-100 cursor-pointer" for="Orange">-->
<!-- </label>-->
<!-- </div>-->
<span class="mx-2 w-auto text-sm text-gray-500 tracking-wide">
<!-- <div>-->
<!-- <div class="relative inline-block w-10 mr-2 align-middle select-none">-->
<!-- bind:checked={nocopyright}-->
<input checked={nocopyright} class="toggle" id="Orange"
name="toggle" on:change={(event) => handleClick(event)}
type="checkbox"/>
<!-- <label class="block overflow-hidden h-6 rounded-full bg-gray-100 cursor-pointer" for="Orange">-->
<!-- </label>-->
<!-- </div>-->
<span class="mx-2 w-auto text-sm text-gray-500 tracking-wide">
是否转载
</span>
<!-- </div>-->
<!-- </div>-->
<div class="pl-4 invisible flex-grow" class:copyright={nocopyright}>
<input bind:value={selectedTemplate.source} class="input input-bordered w-full" id="rounded-email"
placeholder="转载来源"
@@ -256,16 +287,16 @@
</label>
</div>
{/if}
<div class="flex w-52" use:archivePre={{callback, current, currentChildren}}>
<button class="border border-gray-300 relative w-full bg-white rounded-md pl-3 pr-10 py-3 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
type="button">
<div class="flex">
<div class="flex w-52" use:archivePre={{callback, current, currentChildren}}>
<button class="border border-gray-300 relative w-full bg-white rounded-md pl-3 pr-10 py-3 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
type="button">
<span class="flex items-center">
<span class="ml-1 block truncate">
{parent} → {children}
</span>
</span>
<span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg aria-hidden="true" class="h-5 w-5 text-gray-400" fill="currentColor"
viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd"
@@ -274,12 +305,37 @@
</path>
</svg>
</span>
</button>
<!-- <input bind:this={archivePre} bind:value={tid} type="text" class=" rounded-lg border-transparent flex-1 appearance-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent" placeholder="分区"/>-->
</button>
<!-- <input bind:this={archivePre} bind:value={tid} type="text" class=" rounded-lg border-transparent flex-1 appearance-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent" placeholder="分区"/>-->
</div>
<!-- <div class="flex w-48">-->
<!-- <select class="border border-gray-300 relative w-full bg-white rounded-md pl-3 pr-10 py-3 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"-->
<!-- type="button" bind:value={selectedTemplate.uploader}>-->
<!-- {#each uploaders as uploader}-->
<!-- <option class="text-xl" value={uploader}>-->
<!-- {uploader}-->
<!-- </option>-->
<!-- {/each}-->
<!-- <span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">-->
<!-- <svg aria-hidden="true" class="h-5 w-5 text-gray-400" fill="currentColor"-->
<!-- viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">-->
<!-- <path clip-rule="evenodd"-->
<!-- d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"-->
<!-- fill-rule="evenodd">-->
<!-- </path>-->
<!-- </svg>-->
<!-- </span>-->
<!-- </select>-->
<!-- </div>-->
</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 tags as tag(tag)}
<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 ">
<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 ">
{tag}
<button on:click={(e)=>{removeTag(tag)}} class="bg-transparent hover">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor"
@@ -291,7 +347,9 @@
</span>
{/each}
<input bind:value={tempTag} 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' && handleKeypress()}
<input bind:value={tempTag}
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' && handleKeypress()}
placeholder="标签"
type="text"/>
</div>
+1 -1
View File
@@ -3,7 +3,7 @@ import { writable } from "svelte/store";
import { crossfade, fly } from "svelte/transition";
export const isLogin = writable(true);
export const isLogin = writable(false);
export const template = writable({});
export const currentTemplate = writable({
-2046
View File
File diff suppressed because it is too large. Load diff