123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- use crate::{
- cache::Cache,
- error::NtitledError,
- htmx::{DirHtmx, FileHtmx, SubtitleResponseHtmx},
- ost::{data::SubtitleResponse, hash::compute_hash},
- FileType, State,
- };
- use axum::{
- http::{header, StatusCode},
- response::IntoResponse,
- };
- use htmxpress::HtmxElement;
- use minijinja::context;
- use serde::Deserialize;
- use std::{ffi::OsStr, fmt::Write, path::Path};
- use tracing::info;
- pub async fn get_directory(
- mut state: axum::extract::State<State>,
- req: axum::extract::Request,
- ) -> Result<impl IntoResponse, NtitledError> {
- // Strip /dir/
- let path = &req.uri().path()[5..];
- let path = if path == "root" {
- state.base_path.clone()
- } else {
- let path = urlencoding::decode(path)?;
- format!("{}/{path}", state.base_path)
- };
- info!("Listing {path}");
- let files = state.scan_dir_contents(path)?;
- let response = files
- .into_iter()
- .enumerate()
- .fold(String::new(), |mut acc, (i, entry)| {
- match entry {
- FileType::Directory(mut dir) => {
- let Some((_, path)) = dir.path.split_once(&state.base_path) else {
- return acc;
- };
- dir.path = path[1..].to_string();
- let dir: DirHtmx = dir.into();
- let _ = write!(acc, "{}", dir.to_htmx());
- }
- FileType::File(mut file) => {
- let Some((_, path)) = file.path.split_once(&state.base_path) else {
- return acc;
- };
- file.path = path[1..].to_string();
- let file = FileHtmx::new(i, file);
- let _ = write!(acc, "{}", file.to_htmx());
- }
- };
- acc
- });
- let template = state.env.get_template("index").unwrap();
- let template = template.render(context! {divs => response}).unwrap();
- Ok((
- StatusCode::OK,
- [(header::CONTENT_TYPE, "text/html")],
- template,
- ))
- }
- #[derive(Debug, Deserialize)]
- pub struct SubtitleSearch {
- /// Used as the query.
- name: String,
- /// Used for the file hash.
- path: String,
- }
- pub async fn search_subtitles(
- state: axum::extract::State<State>,
- query: axum::extract::Query<SubtitleSearch>,
- ) -> Result<String, NtitledError> {
- let path = format!("{}/{}", state.base_path, &query.path);
- info!("Computing hash for {}", &path);
- let hash = compute_hash(&path)?;
- info!("Searching subtitles for {}", &query.name);
- let search = state.client.search(&query.name, Some(&hash)).await?;
- let mut response = search.data.into_iter().fold(String::new(), |mut acc, el| {
- let el = SubtitleResponse::from(el);
- let el = SubtitleResponseHtmx::new(path.clone(), el).to_htmx();
- let _ = write!(acc, "{el}");
- acc
- });
- if response.is_empty() {
- response = "No subtitles found :(".to_string();
- }
- Ok(response)
- }
- #[derive(Debug, Deserialize)]
- pub struct DownloadQuery {
- file_id: String,
- full_path: String,
- }
- pub async fn download_subtitles(
- mut state: axum::extract::State<State>,
- query: axum::extract::Query<DownloadQuery>,
- ) -> Result<String, NtitledError> {
- let file_id = urlencoding::decode(&query.file_id)?.parse()?;
- let full_path = urlencoding::decode(&query.full_path)?.to_string();
- let file = full_path.split('/').last();
- if let Some(file) = file {
- info!("Downloading subtitles for {file}");
- }
- let ext = Path::new(&full_path).extension().and_then(OsStr::to_str);
- let srt_path = ext
- .map(|ext| query.full_path.replace(&format!(".{ext}"), ".srt"))
- .unwrap_or(format!("{full_path}.srt"));
- state.client.download_subtitles(file_id, &srt_path).await?;
- if let Some(name) = file {
- let existing_meta = state
- .cache
- .get_file_meta(&name.replace(&format!(".{}", ext.unwrap_or_default()), ""))?;
- if let Some(mut meta) = existing_meta {
- meta.has_subs = true;
- state.cache.set_file_meta(&meta)?;
- }
- }
- Ok(String::from("Successfully downloaded subtitles"))
- }
|