feat: watch the selected anime in list
This commit is contained in:
parent
e0b8f758fd
commit
ceb8b29d9a
28
src/api.rs
28
src/api.rs
|
@ -1,12 +1,12 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct SearchResult {
|
pub struct SearchResult {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub url: String,
|
|
||||||
pub image: String,
|
|
||||||
pub releaseDate: String,
|
pub releaseDate: String,
|
||||||
pub subOrDub: String,
|
pub subOrDub: String,
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,19 @@ pub struct Search {
|
||||||
pub results: Vec<SearchResult>,
|
pub results: Vec<SearchResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Quality {
|
||||||
|
pub url: String,
|
||||||
|
pub quality: String,
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Watch {
|
||||||
|
pub sources: Vec<Quality>,
|
||||||
|
pub download: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn query_anime(query: String) -> Result<Search, reqwest::Error> {
|
pub async fn query_anime(query: String) -> Result<Search, reqwest::Error> {
|
||||||
reqwest::get(format!(
|
reqwest::get(format!(
|
||||||
"https://altoku-api.vercel.app/anime/gogoanime/{}?page=1",
|
"https://altoku-api.vercel.app/anime/gogoanime/{}?page=1",
|
||||||
|
@ -28,3 +41,14 @@ pub async fn query_anime(query: String) -> Result<Search, reqwest::Error> {
|
||||||
.json::<Search>()
|
.json::<Search>()
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_url(id: String) -> Result<Watch, reqwest::Error> {
|
||||||
|
reqwest::get(format!(
|
||||||
|
"https://altoku-api.vercel.app/anime/gogoanime/watch/{}",
|
||||||
|
id
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.expect("Failed to get from API")
|
||||||
|
.json::<Watch>()
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::api::query_anime;
|
use crate::api::{get_url, query_anime};
|
||||||
use crate::app::{App, AppResult, ResultList};
|
use crate::app::{App, AppResult, ResultList};
|
||||||
use crate::handler::KeyCode::*;
|
use crate::handler::KeyCode::*;
|
||||||
|
|
||||||
use crossterm::event::*;
|
use crossterm::event::*;
|
||||||
use tui_input::backend::crossterm::EventHandler;
|
use tui_input::backend::crossterm::EventHandler;
|
||||||
|
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
/// Handles the key events and updates the state of [`App`].
|
/// Handles the key events and updates the state of [`App`].
|
||||||
pub async fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
pub async fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
|
||||||
match key_event {
|
match key_event {
|
||||||
|
@ -24,6 +26,7 @@ pub async fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<
|
||||||
code: KeyCode::Enter,
|
code: KeyCode::Enter,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
if app.editing {
|
||||||
app.list = ResultList {
|
app.list = ResultList {
|
||||||
state: app.list.state.clone(),
|
state: app.list.state.clone(),
|
||||||
items: query_anime(app.input.to_string()).await.unwrap().results,
|
items: query_anime(app.input.to_string()).await.unwrap().results,
|
||||||
|
@ -33,19 +36,39 @@ pub async fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<
|
||||||
app.editing = false;
|
app.editing = false;
|
||||||
app.input.reset();
|
app.input.reset();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if app.editing == true {
|
if app.editing {
|
||||||
app.input.handle_event(&Event::Key(key_event));
|
app.input.handle_event(&Event::Key(key_event));
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if app.editing != true {
|
if !app.editing {
|
||||||
match key_event.code {
|
match key_event.code {
|
||||||
Char('j') | Down => app.list.next(),
|
Char('j') | Down => app.list.next(),
|
||||||
Char('k') | Up => app.list.previous(),
|
Char('k') | Up => app.list.previous(),
|
||||||
Char('g') => app.go_top(),
|
Char('g') => app.go_top(),
|
||||||
Char('G') => app.go_bottom(),
|
Char('G') => app.go_bottom(),
|
||||||
|
KeyCode::Enter => {
|
||||||
|
if let Some(i) = app.list.state.selected() {
|
||||||
|
let mut url = String::new();
|
||||||
|
for source in get_url(format!("{}-episode-1", app.list.items[i].id.clone()))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.sources
|
||||||
|
{
|
||||||
|
if source.quality == "1080p" {
|
||||||
|
url = source.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = Command::new("mpv")
|
||||||
|
.arg(format!("{}", url))
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute `mpv`");
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/ui.rs
19
src/ui.rs
|
@ -1,9 +1,4 @@
|
||||||
use ratatui::{
|
use ratatui::{prelude::*, style::Style, widgets::*, Frame};
|
||||||
prelude::*,
|
|
||||||
style::Style,
|
|
||||||
widgets::*,
|
|
||||||
Frame,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
|
||||||
|
@ -58,12 +53,16 @@ pub fn render(app: &mut App, frame: &mut Frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = List::new(results)
|
let list = List::new(results)
|
||||||
.block(Block::bordered().title("Search Results").style(match app.editing {
|
.block(
|
||||||
|
Block::bordered()
|
||||||
|
.title("Search Results")
|
||||||
|
.style(match app.editing {
|
||||||
true => Style::default(),
|
true => Style::default(),
|
||||||
false => Style::default().yellow().bold(),
|
false => Style::default().yellow().bold(),
|
||||||
}))
|
}),
|
||||||
.style(Style::default().white())
|
)
|
||||||
.highlight_style(Style::default().add_modifier(Modifier::ITALIC))
|
.style(Style::default().white().not_bold())
|
||||||
|
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||||
.highlight_symbol("┃ ")
|
.highlight_symbol("┃ ")
|
||||||
.repeat_highlight_symbol(true)
|
.repeat_highlight_symbol(true)
|
||||||
.direction(ListDirection::TopToBottom);
|
.direction(ListDirection::TopToBottom);
|
||||||
|
|
Reference in a new issue