mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-07-17 12:11:14 +08:00
@@ -75,6 +75,13 @@ async def enable_rule(bangumi_id: str):
|
||||
return u_response(resp)
|
||||
|
||||
|
||||
@router.get(path="/refresh/poster/all", response_model=APIResponse, dependencies=[Depends(get_current_user)])
|
||||
async def refresh_poster():
|
||||
with TorrentManager() as manager:
|
||||
resp = manager.refresh_poster()
|
||||
return u_response(resp)
|
||||
|
||||
|
||||
@router.get("/reset/all", response_model=APIResponse, dependencies=[Depends(get_current_user)])
|
||||
async def reset_all():
|
||||
with TorrentManager() as manager:
|
||||
|
||||
@@ -9,13 +9,13 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SeasonCollector(DownloadClient):
|
||||
def collect_season(self, bangumi: Bangumi, link: str = None):
|
||||
def collect_season(self, bangumi: Bangumi, link: str = None, limit: int = None):
|
||||
logger.info(
|
||||
f"Start collecting {bangumi.official_title} Season {bangumi.season}..."
|
||||
)
|
||||
with SearchTorrent() as st:
|
||||
if not link:
|
||||
torrents = st.search_season(bangumi)
|
||||
torrents = st.search_season(bangumi, limit=limit)
|
||||
else:
|
||||
torrents = st.get_torrents(link, bangumi.filter.replace(",", "|"))
|
||||
if self.add_torrent(torrents, bangumi):
|
||||
@@ -23,6 +23,7 @@ class SeasonCollector(DownloadClient):
|
||||
bangumi.eps_collect = True
|
||||
with RSSEngine() as engine:
|
||||
engine.bangumi.update(bangumi)
|
||||
engine.torrent.add_all(torrents)
|
||||
return ResponseModel(
|
||||
status=True,
|
||||
status_code=200,
|
||||
@@ -57,7 +58,7 @@ def eps_complete():
|
||||
logger.info("Start collecting full season...")
|
||||
for data in datas:
|
||||
if not data.eps_collect:
|
||||
with SeasonCollector() as sc:
|
||||
sc.collect_season(data)
|
||||
with SeasonCollector() as collector:
|
||||
collector.collect_season(data)
|
||||
data.eps_collect = True
|
||||
engine.bangumi.update_all(datas)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import logging
|
||||
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from module.database import Database
|
||||
from module.downloader import DownloadClient
|
||||
from module.models import Bangumi, BangumiUpdate, ResponseModel
|
||||
from module.parser import TitleParser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -133,6 +133,18 @@ class TorrentManager(Database):
|
||||
msg_zh=f"无法找到 id {bangumi_id} 的数据",
|
||||
)
|
||||
|
||||
def refresh_poster(self):
|
||||
bangumis = self.bangumi.search_all()
|
||||
for bangumi in bangumis:
|
||||
if not bangumi.poster_link:
|
||||
TitleParser().tmdb_poster_parser(bangumi)
|
||||
self.bangumi.update_all(bangumis)
|
||||
return ResponseModel(
|
||||
status_code=200,
|
||||
status=True,
|
||||
msg_en=f"Refresh poster link successfully.",
|
||||
msg_zh=f"刷新海报链接成功。",
|
||||
)
|
||||
|
||||
def search_all_bangumi(self):
|
||||
datas = self.bangumi.search_all()
|
||||
@@ -152,3 +164,7 @@ class TorrentManager(Database):
|
||||
)
|
||||
else:
|
||||
return data
|
||||
|
||||
if __name__ == '__main__':
|
||||
with TorrentManager() as manager:
|
||||
manager.refresh_poster()
|
||||
|
||||
@@ -30,8 +30,9 @@ class RequestContent(RequestURL):
|
||||
torrents.append(
|
||||
Torrent(name=_title, url=torrent_url, homepage=homepage)
|
||||
)
|
||||
if len(torrents) >= limit:
|
||||
break
|
||||
if isinstance(limit, int):
|
||||
if len(torrents) >= limit:
|
||||
break
|
||||
return torrents
|
||||
else:
|
||||
logger.warning(f"[Network] Failed to get torrents: {_url}")
|
||||
|
||||
@@ -36,6 +36,16 @@ class TitleParser:
|
||||
logger.warning("Please change bangumi info manually.")
|
||||
return title, season, None, None
|
||||
|
||||
@staticmethod
|
||||
def tmdb_poster_parser(bangumi: Bangumi):
|
||||
tmdb_info = tmdb_parser(bangumi.official_title, settings.rss_parser.language)
|
||||
if tmdb_info:
|
||||
logger.debug(f"TMDB Matched, official title is {tmdb_info.title}")
|
||||
bangumi.poster_link = tmdb_info.poster_link
|
||||
else:
|
||||
logger.warning(f"Cannot match {bangumi.official_title} in TMDB. Use raw title instead.")
|
||||
logger.warning("Please change bangumi info manually.")
|
||||
|
||||
@staticmethod
|
||||
def raw_parser(raw: str) -> Bangumi | None:
|
||||
language = settings.rss_parser.language
|
||||
|
||||
@@ -44,7 +44,7 @@ class SearchTorrent(RequestContent, RSSAnalyser):
|
||||
url = search_url(site, keywords)
|
||||
return url
|
||||
|
||||
def search_season(self, data: Bangumi, site: str = "mikan") -> list[Torrent]:
|
||||
def search_season(self, data: Bangumi, site: str = "mikan", limit: int = None) -> list[Torrent]:
|
||||
rss_item = self.special_url(data, site)
|
||||
torrents = self.search_torrents(rss_item)
|
||||
torrents = self.search_torrents(rss_item, limit=limit)
|
||||
return [torrent for torrent in torrents if data.title_raw in torrent.name]
|
||||
@@ -1,129 +1,137 @@
|
||||
import type { BangumiAPI, BangumiRule } from '#/bangumi';
|
||||
import type { ApiSuccess } from '#/api';
|
||||
import type {BangumiAPI, BangumiRule} from '#/bangumi';
|
||||
import type {ApiSuccess} from '#/api';
|
||||
|
||||
|
||||
export const apiBangumi = {
|
||||
/**
|
||||
* 获取所有 bangumi 数据
|
||||
* @returns 所有 bangumi 数据
|
||||
*/
|
||||
async getAll() {
|
||||
const { data } = await axios.get<BangumiAPI[]>('api/v1/bangumi/get/all');
|
||||
const result: BangumiRule[] = data.map((bangumi) => (
|
||||
{
|
||||
...bangumi,
|
||||
filter: bangumi.filter.split(','),
|
||||
rss_link: bangumi.rss_link.split(','),
|
||||
/**
|
||||
* 获取所有 bangumi 数据
|
||||
* @returns 所有 bangumi 数据
|
||||
*/
|
||||
async getAll() {
|
||||
const {data} = await axios.get<BangumiAPI[]>('api/v1/bangumi/get/all');
|
||||
const result: BangumiRule[] = data.map((bangumi) => (
|
||||
{
|
||||
...bangumi,
|
||||
filter: bangumi.filter.split(','),
|
||||
rss_link: bangumi.rss_link.split(','),
|
||||
}
|
||||
));
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取指定 bangumiId 的规则
|
||||
* @param bangumiId bangumi id
|
||||
* @returns 指定 bangumi 的规则
|
||||
*/
|
||||
async getRule(bangumiId: number) {
|
||||
const {data} = await axios.get<BangumiAPI>(
|
||||
`api/v1/bangumi/get/${bangumiId}`
|
||||
);
|
||||
const result: BangumiRule = {
|
||||
...data,
|
||||
filter: data.filter.split(','),
|
||||
rss_link: data.rss_link.split(','),
|
||||
}
|
||||
));
|
||||
return result;
|
||||
},
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取指定 bangumiId 的规则
|
||||
* @param bangumiId bangumi id
|
||||
* @returns 指定 bangumi 的规则
|
||||
*/
|
||||
async getRule(bangumiId: number) {
|
||||
const { data } = await axios.get<BangumiAPI>(
|
||||
`api/v1/bangumi/get/${bangumiId}`
|
||||
);
|
||||
const result: BangumiRule = {
|
||||
...data,
|
||||
filter: data.filter.split(','),
|
||||
rss_link: data.rss_link.split(','),
|
||||
/**
|
||||
* 更新指定 bangumiId 的规则
|
||||
* @param bangumiId - 需要更新的 bangumi 的 id
|
||||
* @param bangumiRule
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async updateRule(bangumiId: number, bangumiRule: BangumiRule) {
|
||||
const rule: BangumiAPI = {
|
||||
...bangumiRule,
|
||||
filter: bangumiRule.filter.join(','),
|
||||
rss_link: bangumiRule.rss_link.join(','),
|
||||
}
|
||||
const post = omit(rule, ['id'])
|
||||
const {data} = await axios.patch<ApiSuccess>(
|
||||
`api/v1/bangumi/update/${bangumiId}`,
|
||||
post
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除指定 bangumiId 的数据库规则,会在重新匹配到后重建
|
||||
* @param bangumiId - 需要删除的 bangumi 的 id
|
||||
* @param file - 是否同时删除关联文件。
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async deleteRule(bangumiId: number | number[], file: boolean) {
|
||||
let url = 'api/v1/bangumi/delete';
|
||||
let ids: undefined | number[];
|
||||
|
||||
if (typeof bangumiId === 'number') {
|
||||
url = `${url}/${bangumiId}`;
|
||||
} else {
|
||||
url = `${url}/many`;
|
||||
ids = bangumiId;
|
||||
}
|
||||
|
||||
const {data} = await axios.delete<ApiSuccess>(url, {
|
||||
data: ids,
|
||||
params: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除指定 bangumiId 的规则。如果 file 为 true,则同时删除关联文件。
|
||||
* @param bangumiId - 需要删除规则的 bangumi 的 id。
|
||||
* @param file - 是否同时删除关联文件。
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async disableRule(bangumiId: number | number[], file: boolean) {
|
||||
let url = 'api/v1/bangumi/disable';
|
||||
let ids: undefined | number[];
|
||||
|
||||
if (typeof bangumiId === 'number') {
|
||||
url = `${url}/${bangumiId}`;
|
||||
} else {
|
||||
url = `${url}/many`;
|
||||
ids = bangumiId;
|
||||
}
|
||||
|
||||
const {data} = await axios.delete<ApiSuccess>(url, {
|
||||
data: ids,
|
||||
params: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 启用指定 bangumiId 的规则
|
||||
* @param bangumiId - 需要启用的 bangumi 的 id
|
||||
*/
|
||||
async enableRule(bangumiId: number) {
|
||||
const {data} = await axios.get<ApiSuccess>(
|
||||
`api/v1/bangumi/enable/${bangumiId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 重置所有 bangumi 数据
|
||||
*/
|
||||
async resetAll() {
|
||||
const {data} = await axios.get<ApiSuccess>('api/v1/bangumi/reset/all');
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 刷新所有没有海报的 bangumi 海报
|
||||
*/
|
||||
async refreshPoster() {
|
||||
const {data} = await axios.get<ApiSuccess>('api/v1/bangumi/refresh/poster/all');
|
||||
return data;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新指定 bangumiId 的规则
|
||||
* @param bangumiId - 需要更新的 bangumi 的 id
|
||||
* @param bangumiRule
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async updateRule(bangumiId: number, bangumiRule: BangumiRule) {
|
||||
const rule: BangumiAPI = {
|
||||
...bangumiRule,
|
||||
filter: bangumiRule.filter.join(','),
|
||||
rss_link: bangumiRule.rss_link.join(','),
|
||||
}
|
||||
const post = omit(rule, ['id'])
|
||||
const { data } = await axios.patch< ApiSuccess >(
|
||||
`api/v1/bangumi/update/${bangumiId}`,
|
||||
post
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除指定 bangumiId 的数据库规则,会在重新匹配到后重建
|
||||
* @param bangumiId - 需要删除的 bangumi 的 id
|
||||
* @param file - 是否同时删除关联文件。
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async deleteRule(bangumiId: number | number[], file: boolean) {
|
||||
let url = 'api/v1/bangumi/delete';
|
||||
let ids: undefined | number[];
|
||||
|
||||
if (typeof bangumiId === 'number') {
|
||||
url = `${url}/${bangumiId}`;
|
||||
} else {
|
||||
url = `${url}/many`;
|
||||
ids = bangumiId;
|
||||
}
|
||||
|
||||
const { data } = await axios.delete< ApiSuccess >(url, {
|
||||
data: ids,
|
||||
params: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除指定 bangumiId 的规则。如果 file 为 true,则同时删除关联文件。
|
||||
* @param bangumiId - 需要删除规则的 bangumi 的 id。
|
||||
* @param file - 是否同时删除关联文件。
|
||||
* @returns axios 请求返回的数据
|
||||
*/
|
||||
async disableRule(bangumiId: number | number[], file: boolean) {
|
||||
let url = 'api/v1/bangumi/disable';
|
||||
let ids: undefined | number[];
|
||||
|
||||
if (typeof bangumiId === 'number') {
|
||||
url = `${url}/${bangumiId}`;
|
||||
} else {
|
||||
url = `${url}/many`;
|
||||
ids = bangumiId;
|
||||
}
|
||||
|
||||
const { data } = await axios.delete< ApiSuccess >(url, {
|
||||
data: ids,
|
||||
params: {
|
||||
file,
|
||||
},
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 启用指定 bangumiId 的规则
|
||||
* @param bangumiId - 需要启用的 bangumi 的 id
|
||||
*/
|
||||
async enableRule(bangumiId: number) {
|
||||
const { data } = await axios.get< ApiSuccess >(
|
||||
`api/v1/bangumi/enable/${bangumiId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* 重置所有 bangumi 数据
|
||||
*/
|
||||
async resetAll() {
|
||||
const { data } = await axios.get< ApiSuccess >('api/v1/bangumi/reset/all');
|
||||
return data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import {Menu, MenuButton, MenuItem, MenuItems} from '@headlessui/vue';
|
||||
import {AddOne, International, More} from '@icon-park/vue-next';
|
||||
import {AddOne, International, More, System} from '@icon-park/vue-next';
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
@@ -54,7 +54,7 @@ function abLabel(label: string | (() => string)) {
|
||||
/>
|
||||
|
||||
<MenuButton bg-transparent is-btn btn-click>
|
||||
<More theme="outline" size="24" fill="#fff"/>
|
||||
<System theme="outline" size="24" fill="#fff"/>
|
||||
</MenuButton>
|
||||
|
||||
<ab-status :running="running"/>
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
Power,
|
||||
Refresh,
|
||||
} from '@icon-park/vue-next';
|
||||
import { ruleTemplate } from "#/bangumi";
|
||||
import {ruleTemplate} from "#/bangumi";
|
||||
import type {BangumiRule} from "#/bangumi";
|
||||
|
||||
const {t, changeLocale} = useMyI18n();
|
||||
@@ -18,6 +18,7 @@ const showAddRSS = ref(false);
|
||||
const searchRule = ref<BangumiRule>()
|
||||
|
||||
const {start, pause, shutdown, restart, resetRule} = useProgramStore();
|
||||
const {refreshPoster} = useBangumiStore();
|
||||
|
||||
const items = [
|
||||
{
|
||||
@@ -46,12 +47,18 @@ const items = [
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
label: () => t('topbar.refresh_poster'),
|
||||
icon: Refresh,
|
||||
handle: refreshPoster
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: () => t('topbar.reset_rule'),
|
||||
icon: Format,
|
||||
handle: resetRule,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
id: 7,
|
||||
label: () => t('topbar.profile.title'),
|
||||
icon: Me,
|
||||
handle: () => {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"restart": "Restart",
|
||||
"shutdown": "Shutdown",
|
||||
"reset_rule": "Reset Rule",
|
||||
"refresh_poster": "Refresh Poster",
|
||||
"search": {
|
||||
"placeholder": "Type to search"
|
||||
},
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"restart": "重启",
|
||||
"shutdown": "关闭",
|
||||
"reset_rule": "重置规则",
|
||||
"refresh_poster": "刷新海报",
|
||||
"search": {
|
||||
"placeholder": "输入关键字搜索"
|
||||
},
|
||||
|
||||
@@ -1,88 +1,94 @@
|
||||
import type { BangumiRule } from '#/bangumi';
|
||||
import { ruleTemplate } from '#/bangumi';
|
||||
import type { ApiSuccess } from '#/api';
|
||||
import type {BangumiRule} from '#/bangumi';
|
||||
import {ruleTemplate} from '#/bangumi';
|
||||
import type {ApiSuccess} from '#/api';
|
||||
|
||||
export const useBangumiStore = defineStore('bangumi', () => {
|
||||
const message = useMessage();
|
||||
const message = useMessage();
|
||||
|
||||
const bangumi = ref<BangumiRule[]>();
|
||||
const editRule = reactive<{
|
||||
show: boolean;
|
||||
item: BangumiRule;
|
||||
}>({
|
||||
show: false,
|
||||
item: ruleTemplate,
|
||||
});
|
||||
const bangumi = ref<BangumiRule[]>();
|
||||
const editRule = reactive<{
|
||||
show: boolean;
|
||||
item: BangumiRule;
|
||||
}>({
|
||||
show: false,
|
||||
item: ruleTemplate,
|
||||
});
|
||||
|
||||
const { execute: getAll, onResult: onBangumiResult } = useApi(
|
||||
apiBangumi.getAll
|
||||
);
|
||||
const { execute: updateRule, onResult: onUpdateRuleResult } = useApi(
|
||||
apiBangumi.updateRule
|
||||
);
|
||||
const { execute: enableRule, onResult: onEnableRuleResult } = useApi(
|
||||
apiBangumi.enableRule
|
||||
);
|
||||
const { execute: disableRule, onResult: onDisableRuleResult } = useApi(
|
||||
apiBangumi.disableRule
|
||||
);
|
||||
const { execute: deleteRule, onResult: onDeleteRuleResult } = useApi(
|
||||
apiBangumi.deleteRule
|
||||
);
|
||||
const {execute: getAll, onResult: onBangumiResult} = useApi(
|
||||
apiBangumi.getAll
|
||||
);
|
||||
const {execute: updateRule, onResult: onUpdateRuleResult} = useApi(
|
||||
apiBangumi.updateRule
|
||||
);
|
||||
const {execute: enableRule, onResult: onEnableRuleResult} = useApi(
|
||||
apiBangumi.enableRule
|
||||
);
|
||||
const {execute: disableRule, onResult: onDisableRuleResult} = useApi(
|
||||
apiBangumi.disableRule
|
||||
);
|
||||
const {execute: deleteRule, onResult: onDeleteRuleResult} = useApi(
|
||||
apiBangumi.deleteRule
|
||||
);
|
||||
const {execute: refreshPoster, onResult: onRefreshPosterResult} = useApi(
|
||||
apiBangumi.refreshPoster
|
||||
);
|
||||
|
||||
onBangumiResult((res) => {
|
||||
function sort(arr: BangumiRule[]) {
|
||||
return arr.sort((a, b) => b.id - a.id);
|
||||
onBangumiResult((res) => {
|
||||
function sort(arr: BangumiRule[]) {
|
||||
return arr.sort((a, b) => b.id - a.id);
|
||||
}
|
||||
|
||||
const enabled = sort(res.filter((e) => !e.deleted));
|
||||
const disabled = sort(res.filter((e) => e.deleted));
|
||||
|
||||
bangumi.value = [...enabled, ...disabled];
|
||||
});
|
||||
|
||||
function refresh() {
|
||||
editRule.show = false;
|
||||
getAll();
|
||||
}
|
||||
|
||||
const enabled = sort(res.filter((e) => !e.deleted));
|
||||
const disabled = sort(res.filter((e) => e.deleted));
|
||||
|
||||
bangumi.value = [...enabled, ...disabled];
|
||||
});
|
||||
|
||||
function refresh() {
|
||||
editRule.show = false;
|
||||
getAll();
|
||||
}
|
||||
|
||||
function actionSuccess(apiRes: ApiSuccess) {
|
||||
message.success(apiRes.msg_en);
|
||||
refresh();
|
||||
}
|
||||
onUpdateRuleResult(actionSuccess);
|
||||
onDisableRuleResult(actionSuccess);
|
||||
onEnableRuleResult(actionSuccess);
|
||||
onDeleteRuleResult(actionSuccess);
|
||||
|
||||
function openEditPopup(data: BangumiRule) {
|
||||
editRule.show = true;
|
||||
editRule.item = data;
|
||||
}
|
||||
|
||||
function ruleManage(
|
||||
type: 'disable' | 'delete',
|
||||
id: number,
|
||||
deleteFile: boolean
|
||||
) {
|
||||
if (type === 'disable') {
|
||||
disableRule(id, deleteFile);
|
||||
function actionSuccess(apiRes: ApiSuccess) {
|
||||
message.success(apiRes.msg_en);
|
||||
refresh();
|
||||
}
|
||||
if (type === 'delete') {
|
||||
deleteRule(id, deleteFile);
|
||||
|
||||
onUpdateRuleResult(actionSuccess);
|
||||
onDisableRuleResult(actionSuccess);
|
||||
onEnableRuleResult(actionSuccess);
|
||||
onDeleteRuleResult(actionSuccess);
|
||||
onRefreshPosterResult(actionSuccess);
|
||||
|
||||
function openEditPopup(data: BangumiRule) {
|
||||
editRule.show = true;
|
||||
editRule.item = data;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
bangumi,
|
||||
editRule,
|
||||
function ruleManage(
|
||||
type: 'disable' | 'delete',
|
||||
id: number,
|
||||
deleteFile: boolean
|
||||
) {
|
||||
if (type === 'disable') {
|
||||
disableRule(id, deleteFile);
|
||||
}
|
||||
if (type === 'delete') {
|
||||
deleteRule(id, deleteFile);
|
||||
}
|
||||
}
|
||||
|
||||
getAll,
|
||||
updateRule,
|
||||
enableRule,
|
||||
disableRule,
|
||||
deleteRule,
|
||||
openEditPopup,
|
||||
ruleManage,
|
||||
};
|
||||
return {
|
||||
bangumi,
|
||||
editRule,
|
||||
|
||||
getAll,
|
||||
updateRule,
|
||||
enableRule,
|
||||
disableRule,
|
||||
deleteRule,
|
||||
refreshPoster,
|
||||
openEditPopup,
|
||||
ruleManage,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user