Add test button for conditions

This commit is contained in:
arabcoders 2025-06-03 20:05:13 +03:00
parent bdf50d0ed8
commit 55b2e3e7f2
4 changed files with 141 additions and 7 deletions

View file

@ -871,6 +871,74 @@ class HttpAPI(Common):
await self._notify.emit(Events.CONDITIONS_UPDATE, data=items)
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")
async def presets(self, request: Request) -> Response:
"""

View file

@ -317,3 +317,26 @@ class Conditions(metaclass=Singleton):
continue
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

View file

@ -14,6 +14,10 @@ function alert(msg: string): boolean {
return window.confirm(msg)
}
export default function useConfirm() {
return { confirm, alert, reduceConfirm }
function prompt(msg: string, defaultValue: string = ''): string | null {
return window.prompt(msg, defaultValue)
}
export default function useConfirm() {
return { confirm, alert, prompt, reduceConfirm }
}

View file

@ -66,7 +66,7 @@
</div>
<div class="card-content" v-if="cond?.raw">
<div class="content">
<pre><code>{{ filterItem(cond) }}</code></pre>
<pre><code>{{ JSON.stringify(cleanObject(cond, remove_keys), null, 2) }}</code></pre>
</div>
</div>
<div class="card-footer mt-auto">
@ -82,6 +82,13 @@
<span>Delete</span>
</button>
</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>
@ -104,6 +111,10 @@
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.
</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>
</Message>
</div>
@ -125,6 +136,7 @@ const toggleForm = ref(false)
const isLoading = ref(false)
const initialLoad = ref(true)
const addInProgress = ref(false)
const remove_keys = ['in_progress', 'raw']
watch(() => config.app.basic_mode, async () => {
if (!config.app.basic_mode) {
@ -236,6 +248,7 @@ const deleteItem = async (item) => {
}
const updateItem = async ({ reference, item }) => {
item = cleanObject(item, remove_keys)
if (reference) {
const index = items.value.findIndex(t => t?.id === reference)
if (index > -1) {
@ -254,10 +267,7 @@ const updateItem = async ({ reference, item }) => {
resetForm(true)
}
const filterItem = item => {
const { raw, ...rest } = item
return JSON.stringify(rest, null, 2)
}
const filterItem = i => JSON.stringify(cleanObject(i, remove_keys), null, 2)
const editItem = _item => {
item.value = _item
@ -287,4 +297,33 @@ const exportItem = item => {
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>