Add test button for conditions
This commit is contained in:
parent
bdf50d0ed8
commit
55b2e3e7f2
4 changed files with 141 additions and 7 deletions
|
|
@ -871,6 +871,74 @@ class HttpAPI(Common):
|
||||||
await self._notify.emit(Events.CONDITIONS_UPDATE, data=items)
|
await self._notify.emit(Events.CONDITIONS_UPDATE, data=items)
|
||||||
return web.json_response(data=items, status=web.HTTPOk.status_code, dumps=self.encoder.encode)
|
return web.json_response(data=items, status=web.HTTPOk.status_code, dumps=self.encoder.encode)
|
||||||
|
|
||||||
|
@route("POST", "api/conditions/test")
|
||||||
|
async def conditions_test(self, request: Request) -> Response:
|
||||||
|
"""
|
||||||
|
Test condition against URL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (Request): The request object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response: The response object
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = await request.json()
|
||||||
|
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return web.json_response(
|
||||||
|
{"error": "Invalid request body expecting dict."},
|
||||||
|
status=web.HTTPBadRequest.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
url = data.get("url")
|
||||||
|
if not url:
|
||||||
|
return web.json_response({"error": "url is required."}, status=web.HTTPBadRequest.status_code)
|
||||||
|
|
||||||
|
cond = data.get("condition")
|
||||||
|
if not cond:
|
||||||
|
return web.json_response({"error": "condition name is required."}, status=web.HTTPBadRequest.status_code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
opts = {}
|
||||||
|
|
||||||
|
if ytdlp_proxy := self.config.get_ytdlp_args().get("proxy", None):
|
||||||
|
opts["proxy"] = ytdlp_proxy
|
||||||
|
|
||||||
|
preset = data.get("preset", self.config.default_preset)
|
||||||
|
ytdlp_opts = YTDLPOpts.get_instance().preset(name=preset, with_cookies=True).add(opts).get_all()
|
||||||
|
key = self.cache.hash(url + str(preset))
|
||||||
|
if not self.cache.has(key):
|
||||||
|
data = extract_info(
|
||||||
|
config=ytdlp_opts,
|
||||||
|
url=url,
|
||||||
|
debug=False,
|
||||||
|
no_archive=True,
|
||||||
|
follow_redirect=True,
|
||||||
|
sanitize_info=True,
|
||||||
|
)
|
||||||
|
self.cache.set(key=key, value=data, ttl=600)
|
||||||
|
else:
|
||||||
|
data = self.cache.get(key)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(e)
|
||||||
|
return web.json_response(
|
||||||
|
data={"error": f"Failed to extract video info. '{e!s}'"},
|
||||||
|
status=web.HTTPInternalServerError.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
matched = Conditions.get_instance().single_match(name=cond, info=data)
|
||||||
|
if matched is None:
|
||||||
|
return web.json_response(
|
||||||
|
data={"error": f"Condition '{cond}' doesn't match the data from the URL."},
|
||||||
|
status=web.HTTPNotFound.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
|
return web.json_response(
|
||||||
|
data={"message": f"Condition '{cond}' matched the data from the URL."},
|
||||||
|
status=web.HTTPOk.status_code,
|
||||||
|
)
|
||||||
|
|
||||||
@route("GET", "api/presets")
|
@route("GET", "api/presets")
|
||||||
async def presets(self, request: Request) -> Response:
|
async def presets(self, request: Request) -> Response:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -317,3 +317,26 @@ class Conditions(metaclass=Singleton):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def single_match(self, name: str, info: dict) -> Condition | None:
|
||||||
|
"""
|
||||||
|
Check if condition matches the info dict.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): The condition name to check.
|
||||||
|
info (dict): The info dict to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Condition|None: The condition if found, None otherwise.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if len(self._items) < 1 or not info or not isinstance(info, dict) or len(info) < 1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
item = self.get(name)
|
||||||
|
if not item or not item.filter:
|
||||||
|
return None
|
||||||
|
|
||||||
|
from yt_dlp.utils import match_str
|
||||||
|
|
||||||
|
return item if match_str(item.filter, info) else None
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ function alert(msg: string): boolean {
|
||||||
return window.confirm(msg)
|
return window.confirm(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useConfirm() {
|
function prompt(msg: string, defaultValue: string = ''): string | null {
|
||||||
return { confirm, alert, reduceConfirm }
|
return window.prompt(msg, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useConfirm() {
|
||||||
|
return { confirm, alert, prompt, reduceConfirm }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content" v-if="cond?.raw">
|
<div class="card-content" v-if="cond?.raw">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<pre><code>{{ filterItem(cond) }}</code></pre>
|
<pre><code>{{ JSON.stringify(cleanObject(cond, remove_keys), null, 2) }}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer mt-auto">
|
<div class="card-footer mt-auto">
|
||||||
|
|
@ -82,6 +82,13 @@
|
||||||
<span>Delete</span>
|
<span>Delete</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer-item">
|
||||||
|
<button class="button is-purple is-fullwidth" @click="TestCondition(cond)"
|
||||||
|
:class="{ 'is-loading': cond?.in_progress }">
|
||||||
|
<span class="icon"><i class="fa-solid fa-play" /></span>
|
||||||
|
<span>Test</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -104,6 +111,10 @@
|
||||||
filter i am able to bypass it <code>availability = 'needs_auth' & channel_id = 'channel_id'</code>.
|
filter i am able to bypass it <code>availability = 'needs_auth' & channel_id = 'channel_id'</code>.
|
||||||
and set proxy for that specific video, while leaving the rest of the videos to be downloaded normally.
|
and set proxy for that specific video, while leaving the rest of the videos to be downloaded normally.
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
The data which the filter is applied on is the same data that yt-dlp returns, simply, click on the
|
||||||
|
information button, and check the data to craft your filter.
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Message>
|
</Message>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -125,6 +136,7 @@ const toggleForm = ref(false)
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const initialLoad = ref(true)
|
const initialLoad = ref(true)
|
||||||
const addInProgress = ref(false)
|
const addInProgress = ref(false)
|
||||||
|
const remove_keys = ['in_progress', 'raw']
|
||||||
|
|
||||||
watch(() => config.app.basic_mode, async () => {
|
watch(() => config.app.basic_mode, async () => {
|
||||||
if (!config.app.basic_mode) {
|
if (!config.app.basic_mode) {
|
||||||
|
|
@ -236,6 +248,7 @@ const deleteItem = async (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateItem = async ({ reference, item }) => {
|
const updateItem = async ({ reference, item }) => {
|
||||||
|
item = cleanObject(item, remove_keys)
|
||||||
if (reference) {
|
if (reference) {
|
||||||
const index = items.value.findIndex(t => t?.id === reference)
|
const index = items.value.findIndex(t => t?.id === reference)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
|
|
@ -254,10 +267,7 @@ const updateItem = async ({ reference, item }) => {
|
||||||
resetForm(true)
|
resetForm(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterItem = item => {
|
const filterItem = i => JSON.stringify(cleanObject(i, remove_keys), null, 2)
|
||||||
const { raw, ...rest } = item
|
|
||||||
return JSON.stringify(rest, null, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
const editItem = _item => {
|
const editItem = _item => {
|
||||||
item.value = _item
|
item.value = _item
|
||||||
|
|
@ -287,4 +297,33 @@ const exportItem = item => {
|
||||||
|
|
||||||
return copyText(base64UrlEncode(JSON.stringify(userData)))
|
return copyText(base64UrlEncode(JSON.stringify(userData)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TestCondition = async (item) => {
|
||||||
|
const url = box.prompt("Enter URL to test condition against:")
|
||||||
|
if (!url) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
item.in_progress = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await request("/api/conditions/test", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ url: url, condition: item.id || item.name }),
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
if (!response.ok) {
|
||||||
|
toast.error(`Failed to test condition. ${data.error}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success(data?.message || "Condition tested successfully.")
|
||||||
|
} catch (e) {
|
||||||
|
toast.error(`Failed to test condition. ${e.message}`)
|
||||||
|
} finally {
|
||||||
|
item.in_progress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue