mirror of
https://github.com/Cp0204/quark-auto-save.git
synced 2026-01-12 23:30:44 +08:00
Compare commits
4 Commits
becaef7f19
...
cdbd2882f3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdbd2882f3 | ||
|
|
dd42197b27 | ||
|
|
9a1ebe0894 | ||
|
|
abc5ef4e40 |
@ -179,12 +179,18 @@ def run_script_now():
|
||||
)
|
||||
|
||||
def generate_output():
|
||||
# 设置环境变量
|
||||
process_env = os.environ.copy()
|
||||
process_env["PYTHONIOENCODING"] = "utf-8"
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
bufsize=1,
|
||||
env=process_env,
|
||||
)
|
||||
try:
|
||||
for line in iter(process.stdout.readline, ""):
|
||||
|
||||
@ -82,19 +82,24 @@
|
||||
|
||||
<div class="row title">
|
||||
<div class="col">
|
||||
<h2>Emby</h2>
|
||||
<h2>媒体库</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label">Emby URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="formData.emby.url" class="form-control" placeholder="可选">
|
||||
<div v-for="(server, serverName) in formData.media_servers" :key="serverName" class="task mb-3">
|
||||
<div class="form-group row" style="display:flex; align-items:center">
|
||||
<div class="col-9" data-toggle="collapse" :data-target="'#collapse_'+serverName" aria-expanded="true" :aria-controls="'collapse_'+serverName">
|
||||
<div class="btn btn-block text-left">
|
||||
<i class="bi bi-caret-right-fill"></i> <span v-html="`${serverName}`"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label">Emby API Key</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="formData.emby.apikey" class="form-control" placeholder="可选">
|
||||
<div class="collapse" :id="'collapse_'+serverName" style="padding-left:2em">
|
||||
<div v-for="(value, key) in server" :key="key" class="form-group row">
|
||||
<label class="col-sm-2 col-form-label">{{ key }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="formData.media_servers[serverName][key]" class="form-control" :placeholder="key === 'url' ? 'URL' : 'API Key/Token'">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -256,9 +261,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label">Emby ID</label>
|
||||
<label class="col-sm-2 col-form-label">媒体库ID</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" name="emby_id[]" class="form-control" v-model="task.emby_id" placeholder="可选">
|
||||
<input type="number" name="media_id[]" class="form-control" v-model="task.media_id" placeholder="可选">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -365,10 +370,7 @@
|
||||
formData: {
|
||||
cookie: [],
|
||||
push_config: {},
|
||||
emby: {
|
||||
url: "",
|
||||
apikey: ""
|
||||
},
|
||||
media_servers: {},
|
||||
tasklist: [],
|
||||
magic_regex: {}
|
||||
},
|
||||
@ -379,7 +381,7 @@
|
||||
pattern: "",
|
||||
replace: "",
|
||||
enddate: "",
|
||||
emby_id: "",
|
||||
media_id: "",
|
||||
ignore_extension: false,
|
||||
runweek: [1, 2, 3, 4, 5, 6, 7]
|
||||
},
|
||||
|
||||
83
media_servers/emby.py
Normal file
83
media_servers/emby.py
Normal file
@ -0,0 +1,83 @@
|
||||
import requests
|
||||
|
||||
|
||||
class Emby:
|
||||
|
||||
default_config = {"url": "", "apikey": ""}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.is_active = False
|
||||
if kwargs:
|
||||
for key, value in self.default_config.items():
|
||||
if key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
else:
|
||||
print(f"{self.__class__.__name__} 模块缺少必要参数: {key}")
|
||||
if self.url and self.apikey:
|
||||
if self.get_info():
|
||||
self.is_active = True
|
||||
|
||||
def get_info(self):
|
||||
url = f"{self.url}/emby/System/Info"
|
||||
headers = {"X-Emby-Token": self.apikey}
|
||||
querystring = {}
|
||||
response = requests.request("GET", url, headers=headers, params=querystring)
|
||||
if "application/json" in response.headers["Content-Type"]:
|
||||
response = response.json()
|
||||
print(
|
||||
f"Emby媒体库: {response.get('ServerName','')} v{response.get('Version','')}"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
print(f"Emby媒体库: 连接失败❌ {response.text}")
|
||||
return False
|
||||
|
||||
def refresh(self, emby_id):
|
||||
if emby_id:
|
||||
url = f"{self.url}/emby/Items/{emby_id}/Refresh"
|
||||
headers = {"X-Emby-Token": self.apikey}
|
||||
querystring = {
|
||||
"Recursive": "true",
|
||||
"MetadataRefreshMode": "FullRefresh",
|
||||
"ImageRefreshMode": "FullRefresh",
|
||||
"ReplaceAllMetadata": "false",
|
||||
"ReplaceAllImages": "false",
|
||||
}
|
||||
response = requests.request(
|
||||
"POST", url, headers=headers, params=querystring
|
||||
)
|
||||
if response.text == "":
|
||||
print(f"🎞 刷新Emby媒体库:成功✅")
|
||||
return True
|
||||
else:
|
||||
print(f"🎞 刷新Emby媒体库:{response.text}❌")
|
||||
return False
|
||||
|
||||
def search(self, media_name):
|
||||
if media_name:
|
||||
url = f"{self.url}/emby/Items"
|
||||
headers = {"X-Emby-Token": self.apikey}
|
||||
querystring = {
|
||||
"IncludeItemTypes": "Series",
|
||||
"StartIndex": 0,
|
||||
"SortBy": "SortName",
|
||||
"SortOrder": "Ascending",
|
||||
"ImageTypeLimit": 0,
|
||||
"Recursive": "true",
|
||||
"SearchTerm": media_name,
|
||||
"Limit": 10,
|
||||
"IncludeSearchTypes": "false",
|
||||
}
|
||||
response = requests.request("GET", url, headers=headers, params=querystring)
|
||||
if "application/json" in response.headers["Content-Type"]:
|
||||
response = response.json()
|
||||
if response.get("Items"):
|
||||
for item in response["Items"]:
|
||||
if item["IsFolder"]:
|
||||
print(
|
||||
f"🎞 《{item['Name']}》匹配到Emby媒体库ID:{item['Id']}"
|
||||
)
|
||||
return item["Id"]
|
||||
else:
|
||||
print(f"🎞 搜索Emby媒体库:{response.text}❌")
|
||||
return False
|
||||
@ -1,6 +1,6 @@
|
||||
# !/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Modify: 2024-04-03
|
||||
# Modify: 2024-11-13
|
||||
# Repo: https://github.com/Cp0204/quark_auto_save
|
||||
# ConfigFile: quark_config.json
|
||||
"""
|
||||
@ -14,6 +14,7 @@ import json
|
||||
import time
|
||||
import random
|
||||
import requests
|
||||
import importlib
|
||||
from datetime import datetime
|
||||
|
||||
# 兼容青龙
|
||||
@ -686,79 +687,24 @@ class Quark:
|
||||
return is_rename_count > 0
|
||||
|
||||
|
||||
class Emby:
|
||||
def __init__(self, emby_url, emby_apikey):
|
||||
self.is_active = False
|
||||
if emby_url and emby_apikey:
|
||||
self.emby_url = emby_url
|
||||
self.emby_apikey = emby_apikey
|
||||
if self.get_info():
|
||||
self.is_active = True
|
||||
|
||||
def get_info(self):
|
||||
url = f"{self.emby_url}/emby/System/Info"
|
||||
headers = {"X-Emby-Token": self.emby_apikey}
|
||||
querystring = {}
|
||||
response = requests.request("GET", url, headers=headers, params=querystring)
|
||||
if "application/json" in response.headers["Content-Type"]:
|
||||
response = response.json()
|
||||
print(
|
||||
f"Emby媒体库: {response.get('ServerName','')} v{response.get('Version','')}"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
print(f"Emby媒体库: 连接失败❌ {response.text}")
|
||||
return False
|
||||
|
||||
def refresh(self, emby_id):
|
||||
if emby_id:
|
||||
url = f"{self.emby_url}/emby/Items/{emby_id}/Refresh"
|
||||
headers = {"X-Emby-Token": self.emby_apikey}
|
||||
querystring = {
|
||||
"Recursive": "true",
|
||||
"MetadataRefreshMode": "FullRefresh",
|
||||
"ImageRefreshMode": "FullRefresh",
|
||||
"ReplaceAllMetadata": "false",
|
||||
"ReplaceAllImages": "false",
|
||||
}
|
||||
response = requests.request(
|
||||
"POST", url, headers=headers, params=querystring
|
||||
)
|
||||
if response.text == "":
|
||||
print(f"🎞 刷新Emby媒体库:成功✅")
|
||||
return True
|
||||
def load_media_servers(media_servers_config, media_servers_dir="media_servers"):
|
||||
media_servers = {}
|
||||
available_modules = [
|
||||
f.replace(".py", "") for f in os.listdir(media_servers_dir) if f.endswith(".py")
|
||||
]
|
||||
for module_name in available_modules:
|
||||
try:
|
||||
module = importlib.import_module(f"{media_servers_dir}.{module_name}")
|
||||
ServerClass = getattr(module, module_name.capitalize())
|
||||
# 检查配置中是否存在该模块的配置
|
||||
if module_name in media_servers_config:
|
||||
server_config = media_servers_config[module_name]
|
||||
media_servers[module_name] = ServerClass(**server_config)
|
||||
else:
|
||||
print(f"🎞 刷新Emby媒体库:{response.text}❌")
|
||||
return False
|
||||
|
||||
def search(self, media_name):
|
||||
if media_name:
|
||||
url = f"{self.emby_url}/emby/Items"
|
||||
headers = {"X-Emby-Token": self.emby_apikey}
|
||||
querystring = {
|
||||
"IncludeItemTypes": "Series",
|
||||
"StartIndex": 0,
|
||||
"SortBy": "SortName",
|
||||
"SortOrder": "Ascending",
|
||||
"ImageTypeLimit": 0,
|
||||
"Recursive": "true",
|
||||
"SearchTerm": media_name,
|
||||
"Limit": 10,
|
||||
"IncludeSearchTypes": "false",
|
||||
}
|
||||
response = requests.request("GET", url, headers=headers, params=querystring)
|
||||
if "application/json" in response.headers["Content-Type"]:
|
||||
response = response.json()
|
||||
if response.get("Items"):
|
||||
for item in response["Items"]:
|
||||
if item["IsFolder"]:
|
||||
print(
|
||||
f"🎞 《{item['Name']}》匹配到Emby媒体库ID:{item['Id']}"
|
||||
)
|
||||
return item["Id"]
|
||||
else:
|
||||
print(f"🎞 搜索Emby媒体库:{response.text}❌")
|
||||
return False
|
||||
media_servers_config[module_name] = ServerClass().default_config
|
||||
except (ImportError, AttributeError):
|
||||
print(f"加载模块 {module_name} 失败")
|
||||
return media_servers
|
||||
|
||||
|
||||
def verify_account(account):
|
||||
@ -818,10 +764,7 @@ def do_sign(account):
|
||||
|
||||
|
||||
def do_save(account, tasklist=[]):
|
||||
emby = Emby(
|
||||
CONFIG_DATA.get("emby", {}).get("url", ""),
|
||||
CONFIG_DATA.get("emby", {}).get("apikey", ""),
|
||||
)
|
||||
media_servers = load_media_servers(CONFIG_DATA.get("media_servers", {}))
|
||||
print(f"转存账号: {account.nickname}")
|
||||
# 获取全部保存目录fid
|
||||
account.update_savepath_fid(tasklist)
|
||||
@ -862,17 +805,33 @@ def do_save(account, tasklist=[]):
|
||||
is_new = account.do_save_task(task)
|
||||
is_rename = account.do_rename_task(task)
|
||||
# 刷新媒体库
|
||||
if emby.is_active and (is_new or is_rename) and task.get("emby_id") != "0":
|
||||
if task.get("emby_id"):
|
||||
emby.refresh(task["emby_id"])
|
||||
else:
|
||||
match_emby_id = emby.search(task["taskname"])
|
||||
if match_emby_id:
|
||||
task["emby_id"] = match_emby_id
|
||||
emby.refresh(match_emby_id)
|
||||
for server_name, media_server in media_servers.items():
|
||||
if (
|
||||
media_server.is_active
|
||||
and (is_new or is_rename)
|
||||
and task.get("media_id") != "0"
|
||||
):
|
||||
if task.get("media_id"):
|
||||
media_server.refresh(task["media_id"])
|
||||
else:
|
||||
match_media_id = media_server.search(task["taskname"])
|
||||
if match_media_id:
|
||||
task["media_id"] = match_media_id
|
||||
media_server.refresh(match_media_id)
|
||||
print()
|
||||
|
||||
|
||||
def reaking_change_update():
|
||||
global CONFIG_DATA
|
||||
# print("Update config v0.3.6.1 to 0.3.7")
|
||||
if CONFIG_DATA.get("emby"):
|
||||
CONFIG_DATA.setdefault("media_servers", {})["emby"] = CONFIG_DATA["emby"]
|
||||
del CONFIG_DATA["emby"]
|
||||
for task in CONFIG_DATA.get("tasklist", {}):
|
||||
task["media_id"] = task.get("emby_id", "")
|
||||
del task["emby_id"]
|
||||
|
||||
|
||||
def main():
|
||||
global CONFIG_DATA
|
||||
start_time = datetime.now()
|
||||
@ -900,6 +859,7 @@ def main():
|
||||
print(f"⚙️ 正从 {config_path} 文件中读取配置")
|
||||
with open(config_path, "r", encoding="utf-8") as file:
|
||||
CONFIG_DATA = json.load(file)
|
||||
reaking_change_update()
|
||||
cookie_val = CONFIG_DATA.get("cookie")
|
||||
if not CONFIG_DATA.get("magic_regex"):
|
||||
CONFIG_DATA["magic_regex"] = MAGIC_REGEX
|
||||
|
||||
Loading…
Reference in New Issue
Block a user