ytdlp_ejs/builtin/
quickjs.rs1use crate::provider::JsChallengeError;
4use rquickjs::{Context, Function, Object, Runtime};
5
6pub struct QuickJSJCP {
8 context: Context,
9}
10
11impl QuickJSJCP {
12 pub fn new(code: &str) -> Result<Self, JsChallengeError> {
13 let runtime = Runtime::new()
14 .map_err(|e| JsChallengeError::Runtime(format!("Failed to create runtime: {}", e)))?;
15 let context = Context::full(&runtime)
16 .map_err(|e| JsChallengeError::Runtime(format!("Failed to create context: {}", e)))?;
17
18 context.with(|ctx| {
19 let globals = ctx.globals();
20 let result_obj = Object::new(ctx.clone()).map_err(|e| {
21 JsChallengeError::Runtime(format!("Failed to create object: {}", e))
22 })?;
23 globals
24 .set("_result", result_obj)
25 .map_err(|e| JsChallengeError::Runtime(format!("Failed to set _result: {}", e)))?;
26
27 ctx.eval::<(), _>(code).map_err(|e| {
28 let err_msg = match &e {
29 rquickjs::Error::Exception => {
30 let exc = ctx.catch();
31 if exc.is_null() || exc.is_undefined() {
32 "Exception (no details)".to_string()
33 } else {
34 format!("Exception: {:?}", exc)
35 }
36 }
37 _ => format!("{:?}", e),
38 };
39 JsChallengeError::Runtime(format!("Failed to execute: {}", err_msg))
40 })?;
41
42 Ok::<(), JsChallengeError>(())
43 })?;
44
45 Ok(Self { context })
46 }
47
48 pub fn solve_n(&self, challenge: &str) -> Result<String, JsChallengeError> {
49 self.call_solver("n", challenge)
50 }
51
52 pub fn solve_sig(&self, challenge: &str) -> Result<String, JsChallengeError> {
53 self.call_solver("sig", challenge)
54 }
55
56 fn call_solver(&self, func_name: &str, challenge: &str) -> Result<String, JsChallengeError> {
57 self.context.with(|ctx| {
58 let globals = ctx.globals();
59 let result: Object = globals
60 .get("_result")
61 .map_err(|e| JsChallengeError::Runtime(format!("Failed to get _result: {}", e)))?;
62 let func: Function = result.get(func_name).map_err(|e| {
63 JsChallengeError::Runtime(format!("Failed to get {} function: {}", func_name, e))
64 })?;
65
66 let result: String = func.call((challenge,)).map_err(|e| {
67 let err_msg = match &e {
68 rquickjs::Error::Exception => {
69 let exc = ctx.catch();
70 if exc.is_null() || exc.is_undefined() {
71 "Exception (no details)".to_string()
72 } else {
73 format!("Exception: {:?}", exc)
74 }
75 }
76 _ => format!("{:?}", e),
77 };
78 JsChallengeError::Runtime(format!("Failed to call {}: {}", func_name, err_msg))
79 })?;
80 Ok(result)
81 })
82 }
83}