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) 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:
""" """

View file

@ -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

View file

@ -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 }
} }

View file

@ -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>