Merge pull request #256 from arabcoders/dev
When using external downloader show indicator in the WebUI
This commit is contained in:
commit
53da40b5f5
8 changed files with 93 additions and 11 deletions
|
|
@ -184,8 +184,8 @@ class DownloadQueue(metaclass=Singleton):
|
|||
"""
|
||||
if item.has_extras():
|
||||
for key in item.extras.copy():
|
||||
if not str(key).startswith("playlist"):
|
||||
item.extras.pop(key, None)
|
||||
if not self.keep_extra_key(key):
|
||||
item.extras.pop(key)
|
||||
|
||||
if not entry:
|
||||
return {"status": "error", "msg": "Invalid/empty data was given."}
|
||||
|
|
@ -395,6 +395,10 @@ class DownloadQueue(metaclass=Singleton):
|
|||
.get_all(),
|
||||
}
|
||||
|
||||
if yt_conf.get("external_downloader"):
|
||||
LOG.warning(f"Using external downloader '{yt_conf.get('external_downloader')}' for '{item.url}'.")
|
||||
item.extras.update({"external_downloader": True})
|
||||
|
||||
downloaded, id_dict = self._is_downloaded(file=yt_conf.get("download_archive", None), url=item.url)
|
||||
if downloaded is True and id_dict:
|
||||
message = f"This url with ID '{id_dict.get('id')}' has been downloaded already and recorded in archive."
|
||||
|
|
@ -715,3 +719,17 @@ class DownloadQueue(metaclass=Singleton):
|
|||
return False, None
|
||||
|
||||
return is_downloaded(file, url)
|
||||
|
||||
def keep_extra_key(self, key: str) -> bool:
|
||||
"""
|
||||
Check if the extra key should be kept.
|
||||
|
||||
Args:
|
||||
key (str): The extra key to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the extra key should be kept, False otherwise.
|
||||
|
||||
"""
|
||||
keys = ("playlist", "external_downloader")
|
||||
return any(key == k or key.startswith(k) for k in keys)
|
||||
|
|
|
|||
|
|
@ -134,6 +134,12 @@ class Item:
|
|||
|
||||
preset = item.get("preset")
|
||||
if preset and isinstance(preset, str) and preset != Item._default_preset():
|
||||
from .Presets import Presets
|
||||
|
||||
if not Presets.get_instance().has(preset):
|
||||
msg = f"Preset '{preset}' does not exist."
|
||||
raise ValueError(msg)
|
||||
|
||||
data["preset"] = preset
|
||||
|
||||
if item.get("folder") and isinstance(item.get("folder"), str):
|
||||
|
|
|
|||
|
|
@ -46,12 +46,14 @@ class TargetRequest:
|
|||
method: str
|
||||
url: str
|
||||
headers: list[TargetRequestHeader] = field(default_factory=list)
|
||||
data_key: str = "data"
|
||||
|
||||
def serialize(self) -> dict:
|
||||
return {
|
||||
"type": self.type,
|
||||
"method": self.method,
|
||||
"url": self.url,
|
||||
"data_key": self.data_key,
|
||||
"headers": [h.serialize() for h in self.headers],
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +215,8 @@ class Notification(metaclass=Singleton):
|
|||
try:
|
||||
Notification.validate(target)
|
||||
except ValueError as e:
|
||||
LOG.error(f"Invalid notification target '{target}'. '{e!s}'")
|
||||
name = target.get("name") or target.get("id") or target.get("request", {}).get("url") or "unknown"
|
||||
LOG.error(f"Invalid notification target '{name}'. '{e!s}'")
|
||||
continue
|
||||
|
||||
target = self.make_target(target)
|
||||
|
|
@ -247,6 +250,7 @@ class Notification(metaclass=Singleton):
|
|||
type=target.get("request", {}).get("type", "json"),
|
||||
method=target.get("request", {}).get("method", "POST"),
|
||||
url=target.get("request", {}).get("url"),
|
||||
data_key=target.get("request", {}).get("data_key", "data"),
|
||||
headers=[
|
||||
TargetRequestHeader(
|
||||
key=str(h.get("key", "")).strip(),
|
||||
|
|
@ -288,6 +292,9 @@ class Notification(metaclass=Singleton):
|
|||
msg = "Invalid notification target. No URL found."
|
||||
raise ValueError(msg)
|
||||
|
||||
if "data_key" not in target["request"]:
|
||||
target["request"]["data_key"] = "data"
|
||||
|
||||
if "method" in target["request"] and target["request"]["method"].upper() not in ["POST", "PUT"]:
|
||||
msg = "Invalid notification target. Invalid method found."
|
||||
raise ValueError(msg)
|
||||
|
|
@ -363,10 +370,17 @@ class Notification(metaclass=Singleton):
|
|||
for h in target.request.headers:
|
||||
reqBody["headers"][h.key] = h.value
|
||||
|
||||
reqBody["json" if "json" == target.request.type.lower() else "data"] = self._deep_unpack(ev.serialize())
|
||||
body_key = "json" if "json" == target.request.type.lower() else "data"
|
||||
reqBody[body_key] = self._deep_unpack(ev.serialize())
|
||||
|
||||
if "data" != target.request.data_key:
|
||||
reqBody[body_key][target.request.data_key] = reqBody[body_key]["data"]
|
||||
reqBody[body_key].pop("data", None)
|
||||
|
||||
if "form" == target.request.type.lower():
|
||||
reqBody["data"]["data"] = self._encoder.encode(reqBody["data"]["data"])
|
||||
reqBody[body_key][target.request.data_key] = self._encoder.encode(
|
||||
reqBody[body_key][target.request.data_key]
|
||||
)
|
||||
|
||||
response = await self._client.request(**reqBody)
|
||||
|
||||
|
|
|
|||
|
|
@ -266,6 +266,19 @@ class Presets(metaclass=Singleton):
|
|||
|
||||
return self
|
||||
|
||||
def has(self, id_or_name: str) -> bool:
|
||||
"""
|
||||
Check if the preset exists by id or name.
|
||||
|
||||
Args:
|
||||
id_or_name (str): The id or name of the preset.
|
||||
|
||||
Returns:
|
||||
bool: True if the preset exists, False otherwise.
|
||||
|
||||
"""
|
||||
return self.get(id_or_name) is not None
|
||||
|
||||
def get(self, id_or_name: str) -> Preset | None:
|
||||
"""
|
||||
Get the preset by id or name.
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12 is-clearfix">
|
||||
<div class="column is-6-tablet is-12-mobile">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="on">
|
||||
Select Events
|
||||
|
|
@ -167,6 +167,26 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-6-tablet is-12-mobile">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="data_key">
|
||||
Data field
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<input type="text" class="input" id="data_key" v-model="form.request.data_key"
|
||||
:disabled="addInProgress" required>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-key" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
The field name to use when sending the notification. This is used to identify the data in the
|
||||
request. The default is <code>data</code>.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<div class="field">
|
||||
<label class="label is-inline is-unselectable">
|
||||
|
|
@ -277,7 +297,7 @@ const showImport = useStorage('showImport', false);
|
|||
const import_string = ref('');
|
||||
|
||||
const checkInfo = async () => {
|
||||
const required = ['name', 'request.url', 'request.method', 'request.type'];
|
||||
const required = ['name', 'request.url', 'request.method', 'request.type', 'request.data_key'];
|
||||
for (const key of required) {
|
||||
if (key.includes('.')) {
|
||||
const [parent, child] = key.split('.');
|
||||
|
|
@ -356,6 +376,10 @@ const importItem = async () => {
|
|||
form.request = item.request
|
||||
}
|
||||
|
||||
if (item.data_key) {
|
||||
form.data_key = item.data_key
|
||||
}
|
||||
|
||||
if (item.on) {
|
||||
form.on = item.on
|
||||
}
|
||||
|
|
@ -366,5 +390,4 @@ const importItem = async () => {
|
|||
toast.error(`Failed to import task. ${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -301,6 +301,10 @@ const setStatus = item => {
|
|||
return 'Live Streaming';
|
||||
}
|
||||
|
||||
if ('preparing' === item.status) {
|
||||
return ag(item, 'extras.external_downloader') ? 'External DL' : 'Preparing..';
|
||||
}
|
||||
|
||||
if (!item.status) {
|
||||
return 'Unknown..';
|
||||
}
|
||||
|
|
@ -372,7 +376,7 @@ const updateProgress = (item) => {
|
|||
}
|
||||
|
||||
if ('preparing' === item.status) {
|
||||
return 'Preparing';
|
||||
return ag(item, 'extras.external_downloader') ? 'External downloader.' : 'Preparing';
|
||||
}
|
||||
|
||||
if (null != item.status) {
|
||||
|
|
|
|||
|
|
@ -205,6 +205,10 @@ onMounted(async () => {
|
|||
|
||||
watch(selectedTheme, value => {
|
||||
try {
|
||||
if ('auto' === value) {
|
||||
applyPreferredColorScheme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
|
||||
return
|
||||
}
|
||||
applyPreferredColorScheme(value)
|
||||
} catch (e) { }
|
||||
})
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ div.is-centered {
|
|||
</li>
|
||||
<li>
|
||||
When you set the request type as <code>Form</code>, the event data will be JSON encoded and sent as the
|
||||
and sent as <code>...&data=json_string</code>, only the <code>data</code> field will be JSON encoded. The
|
||||
other keys <code>id</code>, <code>event</code> and <code>created_at</code> will be sent as they are.
|
||||
and sent as <code>...&data_key=json_string</code>, only the <code>data</code> field will be JSON encoded.
|
||||
The other keys <code>id</code>, <code>event</code> and <code>created_at</code> will be sent as they are.
|
||||
</li>
|
||||
<li>We also send two special headers <code>X-Event-ID</code> and <code>X-Event</code> with the request.</li>
|
||||
</ul>
|
||||
|
|
|
|||
Loading…
Reference in a new issue