1#![warn(clippy::all)]
2use cpython::*;
3use crate::thumbnail::ThumbnailArgs;
4use crate::liking::LikingArgs;
5pub use crate::video::*;
6use std::{fs::File, io::Read, path::Path};
7pub mod liking;
24pub mod thumbnail;
26pub mod video;
44
45static PYLIB:&str = include_str!("../pythonlib/lib.py");
46
47pub struct YTClient {
54 gil:GILGuard,
55 module:PyObject,
56 client:PyObject
57}
58impl YTClient {
60 pub fn new_from_secret(data:&str) -> Self {
64 let gil = Python::acquire_gil();
65 let py = gil.python();
66 let types = py.import("types").unwrap();
68 let module = types.call(py, "ModuleType",("lib",),None).unwrap();
69 let local = PyDict::new(py);
70 local.set_item(py, "code", PYLIB).unwrap();
71 local.set_item(py, "m", module.clone_ref(py)).unwrap();
72 py.run("exec(code,m.__dict__)", Some(&local), None).unwrap();
73 let client = module.call_method(py, "client_from_str", (data,), None).unwrap();
74 Self { gil, module, client }
75 }
76 #[deprecated]
79 pub fn from_secret(data:&str) -> Self {
80 let gil = Python::acquire_gil();
81 let py = gil.python();
82 let importlib = py.import("importlib.util").unwrap();
85 let sys = py.import("sys").unwrap();
86 let spec = importlib.call(py, "spec_from_file_location", ("lib","./pythonlib/lib.py",), None).unwrap();
88 let module = importlib.call(py, "module_from_spec", (spec.clone_ref(py),), None).unwrap();
89 let modules = sys.get(py, "modules").unwrap();
90 modules.set_item(py, "lib", module.clone_ref(py)).unwrap();
91 let loader = spec.getattr(py, "loader").unwrap();
92 loader.call_method(py, "exec_module", (module.clone_ref(py),), None).unwrap();
93
94 let client = module.call_method(py, "client_from_str", (data,), None).unwrap();
96 Self { gil,module,client }
97 }
98 pub fn from_secret_path(path:&str) -> std::io::Result<Self> {
100 let dir = std::env::current_dir().unwrap();
101 println!("{dir:?}");
102 let mut file = File::open(path)?;
103 let mut buf = String::new();
104 file.read_to_string(&mut buf)?;
105 let client = Self::new_from_secret(&buf);
106 Ok(client)
107 }
108 pub fn create_upload_options(&self,video_data:VideoData) -> Result<UploadOptions,String> {
111 let py = self.gil.python();
112 if !Path::new(video_data.file).exists() { return Err(String::from("File does not exist")) }
113 let opt = self.module.call_method( py, "Options", (
114 video_data.title,
115 video_data.desc,
116 video_data.keywords.unwrap_or(""),
117 &video_data.category.to_string(),
118 video_data.privacy_status.to_str(),
119 video_data.file,
120 video_data.for_kids
121 ), None).unwrap();
122 Ok(UploadOptions { options: opt })
123 }
124 pub fn rate_video_request(&self,rating_data:LikingArgs) -> Result<(),impl std::fmt::Debug> {
125 let py = self.gil.python();
126 let interaction = self.module.call_method(py, "InteractionArgs", (rating_data.id,rating_data.rating.to_str()), None)?;
127 self.module.call_method(py, "interact_with_video", (self.client.clone_ref(py),interaction), None)?;
128 Ok::<(),PyErr>(())
129 }
130 pub fn upload_request(&self,opt:UploadOptions) -> Result<(),impl std::fmt::Debug> {
132 let py = self.gil.python();
133 self.module.call_method(py, "upload_req", (self.client.clone_ref(py),opt.options), None)?;
134 Ok::<(),PyErr>(())
135 }
136 pub fn set_thumbnail(&self,args:ThumbnailArgs) -> Result<(),impl std::fmt::Debug>{
138 let py = self.gil.python();
139 self.module.call_method(py, "set_thumbnail", (args.id,args.file), None)?;
140 Ok::<(),PyErr>(())
141 }
142}
143
144
145#[test]
146fn test_client() {
147 let client = YTClient::from_secret_path("src/secret.json").unwrap();
148 let video_data = VideoData {
149 title: "cool",
150 desc: "cool video",
151 keywords: Some("cool,video"),
152 category:video::CategoryID::SciTech as u32,
153 privacy_status:video::PrivacyStatus::Private,
154 file:"src/funny.mp4",
155 for_kids:false
156 };
157 let opt = client.create_upload_options(video_data).unwrap();
158 client.upload_request(opt).unwrap();
159}