Merge remote-tracking branch 'origin/master'

This commit is contained in:
Klein
2023-10-12 16:50:26 +08:00
41 changed files with 694 additions and 66 deletions
@@ -2,7 +2,7 @@ package org.example.core.account.Impl;
import org.example.core.account.AccountCenter;
import org.example.core.factory.PlatformFactory;
import org.example.core.mapper.AccountMapper;
import org.example.mapper.AccountMapper;
import org.example.pojo.Account;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@@ -1,7 +1,7 @@
package org.example.core.guard;
import org.example.core.exchange.Exchange;
import org.example.core.mapper.AccountMapper;
import org.example.mapper.AccountMapper;
import org.example.plugin.GuardPlugin;
import org.example.pojo.*;
@@ -0,0 +1,25 @@
package org.example.core.init.moudle;
import org.example.constpool.ConstPool;
import org.example.constpool.ModuleName;
import org.example.init.ModuleInitMachine;
import org.example.log.ChopperLogFactory;
import org.example.log.LoggerType;
import java.util.List;
/**
* <p>用于初始化弹幕模块所需</p>
*
* @author welsir
* @date 2023/7/31 10:11
*/
public class AccountModuleInitMachine extends ModuleInitMachine {
public AccountModuleInitMachine() {
super(List.of(),
ChopperLogFactory.getLogger(LoggerType.Account),
ModuleName.ACCOUNT);
}
}
@@ -1,7 +1,7 @@
package org.example.core.platform;
import org.example.core.factory.PlatformOperation;
import org.example.core.mapper.AccountMapper;
import org.example.mapper.AccountMapper;
import org.example.pojo.Account;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.chrome.ChromeDriver;
@@ -1,4 +1,4 @@
package org.example.core.mapper;
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
@@ -1,4 +1,4 @@
package org.example.core.mapper;
package org.example.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.example.pojo.AccountType;
@@ -1,5 +0,0 @@
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/database?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
@@ -0,0 +1,33 @@
package org.example.core;
import org.example.bean.Barrage;
import org.example.cache.FileCache;
import org.example.core.creeper.file.BarrageSaveFile;
import org.example.exception.FileCacheException;
/**
* @author Genius
* @date 2023/10/10 18:34
**/
public class BarrageFileCache extends FileCache<BarrageSaveFile> {
private final long flagTime = System.currentTimeMillis();
public BarrageFileCache(BarrageSaveFile configFile) throws FileCacheException {
super(configFile, 0, 10 * 1024);
}
@Override
public int append(Object append, String... keys) throws InterruptedException, FileCacheException {
if(append instanceof Barrage){
if (((Barrage) append).getTimeReal() < flagTime) {
long current = System.currentTimeMillis();
((Barrage) append).setTimeReal(current);
((Barrage) append).setTimeIndex(current-flagTime);
}
}
return super.append(append, keys);
}
}
@@ -9,6 +9,7 @@ import org.example.constpool.BarrageModuleConstPool;
import org.example.constpool.FileNameBuilder;
import org.example.core.creeper.file.BarrageSaveFile;
import org.example.core.creeper.loadconfig.LoadBarrageConfig;
import org.example.util.BarrageUtil;
import org.example.util.FileUtil;
import org.example.util.JsonFileUtil;
@@ -3,6 +3,7 @@ package org.example.core.creeper.loadtask;
import org.example.bean.barrage.DouyuBarrage;
import org.example.cache.FileCache;
import org.example.constpool.PluginName;
import org.example.core.BarrageFileCache;
import org.example.core.BarrageTaskMonitor;
import org.example.core.creeper.file.BarrageSaveFile;
import org.example.core.creeper.loadconfig.DouyuLiveBarrageLoadConfig;
@@ -38,7 +39,7 @@ public class DouyuLiveBarrageLoadTask extends WebSocketLoadTask<List<DouyuBarrag
public DouyuLiveBarrageLoadTask(DouyuLiveBarrageLoadConfig loadConfig) throws FileCacheException {
super(loadConfig);
roomId = loadConfig.getRoomId();
fileCache = new FileCache(new BarrageSaveFile<>(loadConfig,new ConcurrentLinkedQueue<>()));
fileCache = new BarrageFileCache(new BarrageSaveFile<>(loadConfig,new ConcurrentLinkedQueue<>()));
}
@Override
@@ -93,7 +94,7 @@ public class DouyuLiveBarrageLoadTask extends WebSocketLoadTask<List<DouyuBarrag
if(douyuBarrage.getTimeReal()==0){
long now = System.currentTimeMillis();
douyuBarrage.setTimeReal(now);
douyuBarrage.setTimeReal(now-startTime);
douyuBarrage.setTimeIndex(now-startTime);
}
list.add(douyuBarrage);
try {
@@ -3,6 +3,7 @@ package org.example.core.creeper.pipline;
import org.example.bean.Barrage;
import org.example.cache.FileCache;
import org.example.constpool.PluginName;
import org.example.core.BarrageFileCache;
import org.example.core.BarrageTaskMonitor;
import org.example.core.creeper.file.BarrageSaveFile;
import org.example.core.creeper.loadconfig.LoadBarrageConfig;
@@ -33,7 +34,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public class BarragePipelineWriteJson<T extends Barrage> implements Pipeline {
private FileCache filecache;
private BarrageFileCache filecache;
private final ConcurrentLinkedQueue<T> cache;
LoadBarrageConfig loadBarrageConfig;
@@ -53,7 +54,7 @@ public class BarragePipelineWriteJson<T extends Barrage> implements Pipeline {
this.loadBarrageConfig = loadBarrageConfig;
this.cache = new ConcurrentLinkedQueue<>();
this.barrageSaveFile = new BarrageSaveFile(loadBarrageConfig, cache);
this.filecache = new FileCache(barrageSaveFile, 0, 10 * 1024);
this.filecache = new BarrageFileCache(barrageSaveFile);
} catch (FileCacheException e) {
throw new RuntimeException(e);
@@ -11,52 +11,52 @@ import java.util.stream.Collectors;
* @date 2023/09/17 23:20
**/
public class BarrageUtil {
public static boolean cutBarrageFile(String inputFilePath,String outputFilePath,long start,long end){
public static boolean cutBarrageFile(String inputFilePath, String outputFilePath, long start, long end) {
try {
Map<String, Object> map = JsonFileUtil.readJsonFile(inputFilePath);
Object barrages = map.get("data");
if(barrages instanceof JSONArray){
if (barrages instanceof JSONArray) {
List<Barrage> list = ((JSONArray) barrages).toJavaList(Barrage.class);
list = list.stream().sorted(Comparator.comparing(Barrage::getTimeReal)).collect(Collectors.toList());
if(list.isEmpty()){
JsonFileUtil.writeJsonFile(outputFilePath,Map.of("data",list,"updateTime",TimeUtil.getNowTime_YMDHMS()));
}else{
if (list.isEmpty()) {
JsonFileUtil.writeJsonFile(outputFilePath, Map.of("data", list, "updateTime", TimeUtil.getNowTime_YMDHMS()));
} else {
long startTime = list.get(0).getTimeReal() + start;
long endTime = list.get(0).getTimeReal() + end;
List<Barrage> newBarrageList = new ArrayList<>();
int endIndex = leTimeBarrageIndex(list,endTime);
int startIndex = geTimeBarrageIndex(list,startTime);
if(endIndex!=-1&&startIndex!=-1){
newBarrageList = List.copyOf(list.subList(startIndex,endIndex+1));
int endIndex = leTimeBarrageIndex(list, endTime);
int startIndex = geTimeBarrageIndex(list, startTime);
if (endIndex != -1 && startIndex != -1) {
newBarrageList = List.copyOf(list.subList(startIndex, endIndex + 1));
}
JsonFileUtil.writeJsonFile(outputFilePath,Map.of("data",newBarrageList,"updateTime",TimeUtil.getNowTime_YMDHMS()));
JsonFileUtil.writeJsonFile(outputFilePath, Map.of("data", newBarrageList, "updateTime", TimeUtil.getNowTime_YMDHMS()));
}
}
}catch (Exception e){
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public static int leTimeBarrageIndex(List<Barrage> barrages,long time){
public static int leTimeBarrageIndex(List<Barrage> barrages, long time) {
int left = 0;
int right = barrages.size() - 1;
int result = -1;
while (left <= right){
int mid = (left + right) / 2;
while (left <= right) {
int mid = (left + right) / 2;
Long timeReal = barrages.get(mid).getTimeReal();
if (timeReal <= time) {
left = mid + 1;
result = mid;
}else{
} else {
right = mid - 1;
}
}
return result;
return result;
}
public static int geTimeBarrageIndex(List<Barrage> barrages,long time){
public static int geTimeBarrageIndex(List<Barrage> barrages, long time) {
int left = 0;
int right = barrages.size() - 1;
int result = -1;
@@ -64,7 +64,7 @@ public class BarrageUtil {
int mid = (left + right) / 2;
Long timeReal = barrages.get(mid).getTimeReal();
if (timeReal >= time) {
right = mid -1;
right = mid - 1;
result = mid;
} else {
left = mid + 1;
@@ -72,5 +72,4 @@ public class BarrageUtil {
}
return result;
}
}
@@ -17,4 +17,5 @@ public class ModuleName {
public static final String BARRAGE = ConstPool.BARRAGE;
public static final String LIVE = ConstPool.LIVE_RECORD;
public static final String SECTION = ConstPool.SECTION;
public static final String ACCOUNT = ConstPool.ACCOUNT;
}
@@ -151,12 +151,17 @@ public class InitPluginRegister {
throw PluginDependOnException.MissingFatherPlugin(needPlugin,pluginName);
}
}
if (initMachine.init()) {
registerPluginTable.put(pluginName,initMachine);
initMachine.afterInit();
return true;
}else{
return false;
try {
if (initMachine.init()) {
registerPluginTable.put(pluginName,initMachine);
initMachine.afterInit();
return true;
}else{
return false;
}
}catch (Exception e){
ChopperLogFactory.getLogger(LoggerType.System)
.error(String.format("❌ %s plugin start failed ! error:%s", pluginName,e.getMessage()));
}
}else{
return false;
@@ -11,6 +11,7 @@ public enum LoggerType {
Hot("HotModule "),
Barrage("Barrage "),
LiveRecord("LiveRecord "),
Account("Account "),
Section("Section ");
private String loggerName;
+12 -6
View File
@@ -18,6 +18,18 @@
</properties>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>chopperbot-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>chopperbot-account</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>chopperbot-creeper</artifactId>
@@ -33,12 +45,6 @@
<artifactId>chopperbot-file</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>chopperbot-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>chopperbot-hot</artifactId>
@@ -5,6 +5,7 @@ import org.example.service.FileService;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@@ -33,4 +34,6 @@ public class FileController {
public Result getAllConfigFiles(){
return Result.success(fileService.getAllConfigs());
}
}
@@ -114,19 +114,44 @@ public class HotController {
);
}
@CheckPlugin(needPlugin = {PluginName.HOT_RECOMMENDATION_PLUGIN})
@GetMapping("/hotRecommendation/list")
public Result followDogs(){
List<FollowDog> followDog = hotModuleService.heatRecommendApi().getFollowDog();
@CheckPlugin(needPlugin = {PluginName.HOT_LIVER_FOLLOWER})
@GetMapping("/liveFollow/changeSetting")
public Result changeLiverFollowSetting(@RequestParam(required = false) Integer focusLive,
@RequestParam(required = false) Integer focusBarrage,
@RequestParam(required = false) Long checkTime){
hotModuleService.liverFollowApi().changeSetting(
Map.of("focusLive",focusLive,
"focusBarrage",focusBarrage,
"checkTime",checkTime
)
);
return Result.success(
Map.of("list",followDog)
Map.of("success",true)
);
}
@CheckPlugin(needPlugin = {PluginName.HOT_LIVER_FOLLOWER})
@GetMapping("/liveFollow/setting")
public Result changeLiverFollowSetting(){
return Result.success(
Map.of("setting",hotModuleService.liverFollowApi().getSetting())
);
}
@CheckPlugin(needPlugin = {PluginName.HOT_RECOMMENDATION_PLUGIN})
@GetMapping("/hotRecommendation/list")
public Result getFollowDogs(){
return Result.success(
Map.of(
"list",hotModuleService.heatRecommendApi().getFollowDog()
)
);
}
@CheckPlugin(needPlugin = {PluginName.HOT_RECOMMENDATION_PLUGIN})
@PostMapping("/hotRecommendation/add")
public Result addFollowDogs(@RequestBody FollowDog dog){
dog.setId(null);
boolean success = hotModuleService.heatRecommendApi().addFollowDog(dog);
if(success){
return Result.success(
@@ -137,6 +162,8 @@ public class HotController {
}
}
@CheckPlugin(needPlugin = {PluginName.HOT_RECOMMENDATION_PLUGIN})
@PostMapping("/hotRecommendation/update")
public Result updateFollowDogs(@RequestBody FollowDog dog){
@@ -1,6 +1,7 @@
package org.example.service;
import org.example.pojo.vo.ConfigVO;
import org.example.util.Result;
import java.util.List;
@@ -16,4 +17,5 @@ public interface FileService {
//获取所有文件
List<ConfigVO> getAllConfigs();
}
@@ -1,11 +1,17 @@
package org.example.util;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import org.example.bean.ConfigFile;
import org.example.cache.FileCache;
import org.example.cache.FileCacheManager;
import org.example.cache.FileCacheManagerInstance;
import org.example.constpool.PluginName;
import org.example.exception.FileCacheException;
import org.example.init.InitPluginRegister;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@@ -48,4 +54,28 @@ public class ConfigFileUtil {
public static boolean createConfigFile(String filePath, ConfigFile configFile){
return createConfigFile(filePath,configFile,null,null,false);
}
public static void changeSetting(Map<String,Object> settings,String filePath,String...prefixParams){
FileCacheManager plugin = InitPluginRegister.getPlugin(PluginName.FILE_CACHE_PLUGIN, FileCacheManager.class);
FileCache fileCache = plugin.getFileCache(filePath);
settings.forEach(
(k,v)->{
try {
if(ObjectUtils.isNotEmpty(v)){
ArrayList<String> list = new ArrayList<String>(List.of(prefixParams));
list.add(k);
fileCache.writeKeys(v, list.toArray(new String[0]));
}
} catch (InterruptedException | FileCacheException e) {
throw new RuntimeException(e);
}
}
);
}
public static Object getSetting(String filePath,String...prefixParams){
FileCacheManager plugin = InitPluginRegister.getPlugin(PluginName.FILE_CACHE_PLUGIN, FileCacheManager.class);
FileCache fileCache = plugin.getFileCache(filePath);
return fileCache.get(prefixParams);
}
}
@@ -1,12 +1,21 @@
package org.example.api;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import org.example.bean.FocusLiver;
import org.example.cache.FileCache;
import org.example.cache.FileCacheManager;
import org.example.config.HotModuleConfig;
import org.example.constpool.PluginName;
import org.example.core.focus.LiverFollower;
import org.example.exception.FileCacheException;
import org.example.init.InitPluginRegister;
import org.example.service.FocusLiverService;
import org.example.util.ConfigFileUtil;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author Genius
@@ -41,4 +50,12 @@ public class LiverFollowApi {
}
return false;
}
public void changeSetting(Map<String,Object> settings){
ConfigFileUtil.changeSetting(settings,HotModuleConfig.getFullFilePath(),"LiverFollower");
}
public Object getSetting(){
return ConfigFileUtil.getSetting(HotModuleConfig.getFullFilePath(),"LiverFollower");
}
}
@@ -33,4 +33,9 @@ public class BilibiliLiverCheckerConfig extends LoadConfig {
this.cookie.put("buvid3","6BA6EB5A-E197-4F47-A2C4-E4022E98BC85138387infoc");
this.cookie.put("SESSDATA","9481d398%2C1711296621%2C4d8e5%2A91CjB4IXMIVvMxEG4t5eeq6jicEzEbBHPyKRAJcBNLSi7n_-bBq8ik86Cua7JRupYgqPoSVl9pM2tHYllWSURiQmxESDByUExXU0kwV01JckN0dlB4Sks4aHk5V1FTOXBsSG9STkVJNnhwakxoS2VscWV6a0taYm0wa2xPVUxMRk9lZ2R5T19mS3FBIIEC");
}
@Override
public String getTaskId() {
return super.getTaskId()+"_"+liver;
}
}
@@ -27,4 +27,9 @@ public class DouyuLiverCheckerConfig extends LoadConfig {
this.roomId = roomId;
this.url = "https://www.douyu.com/betard/"+roomId;
}
@Override
public String getTaskId() {
return super.getTaskId()+"_"+roomId;
}
}
@@ -61,6 +61,7 @@ public class LiverFollower extends SpringBootPlugin {
FileCache fileCache = plugin.getFileCache(HotModuleConfig.getFullFilePath());
focusLive = (Integer)fileCache.get("LiverFollower", "focusLive")==1;
//focusBarrage = (Integer)fileCache.get("LiverFollower", "focusBarrage")==1;
checkTime = Integer.toUnsignedLong((Integer) fileCache.get("LiverFollower", "checkTime"));
focusRecord = (Integer)fileCache.get("LiverFollower", "focusRecord")==1;
checkTime = (Integer)fileCache.get("LiverFollower", "checkTime");
focusLivers = service.getFocusLivers();
@@ -19,7 +19,6 @@ import java.util.concurrent.TimeUnit;
public class bilibiliTest {
public static void getcookies() throws Exception {
System.setProperty("webdriver.chrome.driver", "D:\\downLoad\\chromedriver_win32\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.setBinary("C:\\Program Files (x86)\\Chromebrowser\\Chrome.exe");
+1 -1
View File
@@ -3,7 +3,7 @@
"InstantSlicing":{
"handler":"ScheduleTime",
"ScheduleTime":{
"duration":300000
"duration":600000
}
},
"barrageScoreCurve":{
+8 -8
View File
@@ -1,14 +1,14 @@
{
"updateTime":"2023-09-11 12:56:40",
"data":{
"LiverFollower":{
"checkTime":60000,
"focusLive":1,
"focusRecord":1,
"focusBarrage":1
},
"HotGuard":{
"GuardNum":10
},
"LiverFollower":{
"checkTime":120000,
"focusRecord":1,
"focusLive":1,
"focusBarrage":1
}
}
},
"updateTime":"2023-10-12 01:51:20"
}
+2 -2
View File
@@ -24,12 +24,12 @@
"HotRecommendation":true,
"BarrageScoreCurve":true,
"FileCacheManager":true,
"LiverFollower":false,
"LiverFollower":true,
"TaskMonitor":true,
"HotConfig":true,
"TaskCenter":true,
"CreeperConfig":true
}
},
"updateTime":"2023-10-09 22:41:45"
"updateTime":"2023-10-12 01:50:20"
}
+20 -1
View File
@@ -22,10 +22,29 @@ export function addFollow(liver:FocusLiver){
export function unFollow(platform:string,liver:string){
return request({
url: '/hot/liveFollow/delete',
method: 'Get',
method: 'get',
params: {
platform:platform,
liver:liver
}
});
}
export function getSetting(){
return request({
url: '/hot/liveFollow/setting',
method: 'get',
})
}
export function changeSetting(checkTime:number,focusLive:number,focusBarrage:number){
return request({
url: '/hot/liveFollow/changeSetting',
method: 'get',
params: {
checkTime: checkTime,
focusLive: focusLive,
focusBarrage: focusBarrage
}
})
}
+1 -1
View File
@@ -33,7 +33,7 @@ export default [
icon:"mdi mdi-star-face",
key:"menu.live_follow",
text:"Live Follow",
link: "/apps/live_follow"
link: "/apps/liveFollow"
},
{
icon: "mdi-forum-outline",
+14
View File
@@ -92,6 +92,20 @@ export default [
category: "APP",
},
},
{
path: "/apps/liveFollow",
name: "app-live-follow",
component: () =>
import(
/* webpackChunkName: "utility-board" */ "@/views/app/hot/live_follow/LiveFollowPage.vue"
),
meta: {
requiresAuth: true,
title: "Live Follow",
layout: "ui",
category: "APP",
},
},
{
path: "/apps/email",
meta: {
+8 -1
View File
@@ -1,5 +1,7 @@
import axios from "axios";
import {useSnackbarStore} from "@/stores/snackbarStore";
const snackbarStore = useSnackbarStore();
const request = axios.create({
baseURL: "/appApi",
timeout: 100000,
@@ -16,8 +18,13 @@ request.interceptors.request.use(config => {
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
if(response.status!=200){
snackbarStore.showSuccessMessage("服务异常!")
}
let res = response.data;
if(res.code === 114514){
snackbarStore.showErrorMessage("该插件没有启动,请先启动插件!")
}
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
@@ -1,5 +1,4 @@
import { defineStore } from "pinia";
import {useSnackbarStore} from "@/stores/snackbarStore";
import {FollowDog} from "@/views/app/hot/heat_recommend/FollowDogTypes";
@@ -56,6 +56,11 @@ onMounted(async()=>{
})
})
setInterval(()=>{
getGuards().then(res=>{
hotGuardStore.guards = res.data['list']
})
},30000)
</script>
@@ -0,0 +1,28 @@
<script setup lang="ts">
import {followList} from "@/api/hot/liveFollowApi";
import {useLiveFollowStore} from "@/views/app/hot/live_follow/liveFollowStore";
import LiveFollowCard from "@/views/app/hot/live_follow/component/LiveFollowCard.vue";
const liveFollowStore = useLiveFollowStore();
onMounted(async()=>{
await followList().then(res=>{
liveFollowStore.liveFollowList = res.data['list']
})
})
</script>
<template>
<div class="app-container">
<LiveFollowCard :liveFollows="liveFollowStore.liveFollowList"></LiveFollowCard>
</div>
</template>
<style scoped lang="scss">
.app-container {
height: calc(100vh - 240px);
width: 100%;
font-size: 13px;
padding: 20px;
}
</style>
@@ -0,0 +1,113 @@
<template>
<v-row justify="center">
<v-dialog
v-model="liveFollowStore.addDialog"
persistent
width="1024"
>
<v-card>
<v-card-title>
<span class="text-h5">User Profile</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
label="Legal first name*"
required
></v-text-field>
</v-col>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
label="Legal middle name"
hint="example of helper text only on focus"
></v-text-field>
</v-col>
<v-col
cols="12"
sm="6"
md="4"
>
<v-text-field
label="Legal last name*"
hint="example of persistent helper text"
persistent-hint
required
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
label="Email*"
required
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
label="Password*"
type="password"
required
></v-text-field>
</v-col>
<v-col
cols="12"
sm="6"
>
<v-select
:items="['0-17', '18-29', '30-54', '54+']"
label="Age*"
required
></v-select>
</v-col>
<v-col
cols="12"
sm="6"
>
<v-autocomplete
:items="['Skiing', 'Ice hockey', 'Soccer', 'Basketball', 'Hockey', 'Reading', 'Writing', 'Coding', 'Basejump']"
label="Interests"
multiple
></v-autocomplete>
</v-col>
</v-row>
</v-container>
<small>*indicates required field</small>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue-darken-1"
variant="text"
@click="liveFollowStore.addDialog = false"
>
Close
</v-btn>
<v-btn
color="blue-darken-1"
variant="text"
@click="liveFollowStore.addDialog = false"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
</template>
<script setup lang="ts">
import {useLiveFollowStore} from "@/views/app/hot/live_follow/liveFollowStore";
const liveFollowStore = useLiveFollowStore();
</script>
<style scoped>
</style>
@@ -0,0 +1,134 @@
<script setup lang="ts">
import CopyLabel from "@/components/common/CopyLabel.vue";
import {useLiveFollowStore} from "@/views/app/hot/live_follow/liveFollowStore";
import LiveFollowSetting from "@/views/app/hot/live_follow/component/LiveFollowSetting.vue";
import AddFormDiaLog from "@/views/app/hot/live_follow/component/AddFormDiaLog.vue";
import {FocusLiver} from "@/views/app/hot/live_follow/focusLiverTypes";
const liveFollowStore = useLiveFollowStore();
const props = defineProps<{
liveFollows: FocusLiver[];
}>();
const loading = ref(true);
const headers = [
{ text: "id", align: "start", value: "id" },
{ text: "平台", value: "description" },
{ text: "主播昵称", value: "author" },
{ text: "房间号", value: "group" },
{ text: "标签", value: "priority" },
{ text: "操作", value: "option" },
];
const open = (item) => {};
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
const keys = ["group","name"]
</script>
<template>
<!-- loading spinner -->
<LiveFollowSetting></LiveFollowSetting>
<AddFormDiaLog></AddFormDiaLog>
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<v-card>
<v-card-title class="font-weight-bold">
<span>Live Follow</span>
<v-spacer></v-spacer>
<v-btn
style="margin-right: 20px"
color="success"
@click="liveFollowStore.addDialog = true"
>
<v-icon start icon="mdi mdi-plus-box"></v-icon>
关注主播
</v-btn>
<v-btn
color="primary"
dark
v-bind="props"
@click="liveFollowStore.dialog = true"
>
<v-icon start icon="mdi mdi-cog"></v-icon>
Setting
</v-btn>
</v-card-title>
<v-table class="pa-3">
<thead>
<tr>
<th class="text-left" v-for="header in headers" :key="header.text">
{{ header.text }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in liveFollows" :key="item.id">
<td class="font-weight-bold">
<copy-label :text="`# ${index}`" />
</td>
<td>
<copy-label :text="item.platform" />
</td>
<td>{{ item.liver }}</td>
<td>{{ item.roomId }}</td>
<td>
<v-chip
color="cyan"
label>
<v-icon start icon="mdi mdi-earth-box"></v-icon>
{{ item.tag }}
</v-chip>
</td>
<td>
<v-btn density="comfortable" color="red" icon="mdi mdi-trash-can"></v-btn>
</td>
</tr>
</tbody>
</v-table>
</v-card>
</div>
</template>
<style lang="scss" scoped>
.v-table {
table {
padding: 4px;
padding-bottom: 8px;
th {
text-transform: uppercase;
white-space: nowrap;
}
td {
border-bottom: 0 !important;
}
tbody {
tr {
transition: box-shadow 0.2s, transform 0.2s;
&:not(.v-data-table__selected):hover {
box-shadow: 0 3px 15px -2px rgba(0, 0, 0, 0.12);
transform: translateY(-4px);
}
}
}
}
}
</style>
@@ -0,0 +1,130 @@
<template>
<v-dialog
v-model="liveFollowStore.dialog"
fullscreen
:scrim="false"
transition="dialog-bottom-transition"
>
<v-card>
<v-toolbar
dark
color="primary"
>
<v-btn
icon
dark
@click="liveFollowStore.dialog = false"
>
<v-icon>mdi-close</v-icon>
</v-btn>
<v-toolbar-title>Plugin Setting</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn
variant="text"
@click="save()"
>
Save
</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-list
lines="two"
subheader
>
<v-list-item title="focusLive" subtitle="是否自动爬取关注主播的直播"></v-list-item>
<v-list-item title="focusBarrage" subtitle="是否自动爬取关注主播的直播弹幕(该版本此配置项不生效)"></v-list-item>
<v-list-item title="checkTime" subtitle="多少秒检测一次主播开播情况(单位:毫秒)"></v-list-item>
</v-list>
<v-divider></v-divider>
<v-list
lines="two"
subheader
>
<v-text-field
label="checkTime"
v-model="setting.checkTime"
:rules="timeRules"
hide-details="auto"
></v-text-field>
<v-switch class="flex-col"
style=""
size="small"
v-model="setting.focusLive"
color="green"
label="focusLive"
inset
></v-switch>
<v-switch class="flex-col"
style=""
size="small"
disabled
v-model="setting.focusBarrage"
color="green"
label="focusBarrage"
inset
></v-switch>
</v-list>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import {useLiveFollowStore} from "@/views/app/hot/live_follow/liveFollowStore";
import {changeSetting, getSetting} from "@/api/hot/liveFollowApi";
import {useSnackbarStore} from "@/stores/snackbarStore";
type Setting = {
focusLive: boolean,
focusBarrage: boolean,
checkTime: number,
}
const snackbarStore = useSnackbarStore()
const liveFollowStore = useLiveFollowStore();
const setting = ref<Setting>({
focusLive: false,
focusBarrage: false,
checkTime:0
})
onMounted(()=>{
getSetting().then(res=>{
liveFollowStore.setting = res.data['setting']
setting.value = res.data['setting']
setting.value.focusBarrage = res.data['setting']?.focusBarrage===1
setting.value.focusLive = res.data['setting']?.focusLive===1
})
})
const timeRules = [
(v)=> !!v || "时间必须存在",
(v)=> v > 0 || "时间必须大于0",
(v)=> v >= 1000 || "时间必须大于1s",
]
const save = async () =>{
await changeSetting(setting.value.checkTime,
setting.value.focusLive?1:0,
setting.value.focusBarrage?1:0
).then(res=>{
if(res?.data?.success){
liveFollowStore.dialog = false
snackbarStore.showSuccessMessage("更新设置成功")
}else{
snackbarStore.showSuccessMessage("更新设置失败")
}
})
}
</script>
<style scoped>
.dialog-bottom-transition-enter-active,
.dialog-bottom-transition-leave-active {
transition: transform .2s ease-in-out;
}
</style>
@@ -1,4 +1,5 @@
export interface FocusLiver{
id:number;
liver: string;
roomId: string;
platform: string;
@@ -0,0 +1,21 @@
import { defineStore } from "pinia";
import {FocusLiver} from "@/views/app/hot/live_follow/focusLiverTypes"
export const useLiveFollowStore = defineStore({
id: "hotRecommend",
state:()=>({
dialog: ref(false),
addDialog: ref(false),
setting:ref({}),
liveFollowList: ref<FocusLiver[]>([]),
}),
getters:{
},
actions:{
}
})
BIN
View File
Binary file not shown.