Skip to content

Commit c4abb55

Browse files
Merge pull request #684 from kestrel-x86/FIX-#662
Fix #662
2 parents ad8ee1d + 440f819 commit c4abb55

File tree

6 files changed

+124
-5
lines changed

6 files changed

+124
-5
lines changed

rust-api/src/database.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,42 @@ impl DatabasePool {
22292229
}
22302230
}
22312231

2232+
pub async fn update_episode_duration(&self, episode_id: i32, new_duration: i32, is_youtube: bool) -> AppResult<()> {
2233+
match self {
2234+
DatabasePool::Postgres(pool) => {
2235+
if is_youtube {
2236+
sqlx::query(r#"UPDATE "YouTubeVideos" SET duration = $1 WHERE videoid = $2"#)
2237+
.bind(new_duration)
2238+
.bind(episode_id)
2239+
.execute(pool)
2240+
.await?;
2241+
} else {
2242+
sqlx::query(r#"UPDATE "Episodes" SET episodeduration = $1 WHERE episodeid = $2"#)
2243+
.bind(new_duration)
2244+
.bind(episode_id)
2245+
.execute(pool)
2246+
.await?;
2247+
}
2248+
}
2249+
DatabasePool::MySQL(pool) => {
2250+
if is_youtube {
2251+
sqlx::query(r#"UPDATE YouTubeVideos SET duration = ? WHERE videoid = ?"#)
2252+
.bind(new_duration)
2253+
.bind(episode_id)
2254+
.execute(pool)
2255+
.await?;
2256+
} else {
2257+
sqlx::query(r#"UPDATE Episodes SET episodeduration = ? WHERE episodeid = ?"#)
2258+
.bind(new_duration)
2259+
.bind(episode_id)
2260+
.execute(pool)
2261+
.await?;
2262+
}
2263+
}
2264+
}
2265+
Ok(())
2266+
}
2267+
22322268
// Mark episode as completed - matches Python mark_episode_completed function
22332269
pub async fn mark_episode_completed(&self, episode_id: i32, user_id: i32, is_youtube: bool) -> AppResult<()> {
22342270
match self {

rust-api/src/handlers/podcasts.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,37 @@ pub async fn fetch_podcasting_2_pod_data(
13611361
Ok(Json(data))
13621362
}
13631363

1364+
#[derive(Deserialize)]
1365+
pub struct UpdateEpisodeDurationRequest {
1366+
pub episode_id: i32,
1367+
pub new_duration: i32,
1368+
pub is_youtube: bool,
1369+
}
1370+
1371+
pub async fn update_episode_duration(
1372+
headers: HeaderMap,
1373+
State(state): State<AppState>,
1374+
Json(request): Json<UpdateEpisodeDurationRequest>,
1375+
) -> Result<Json<serde_json::Value>, AppError> {
1376+
let api_key = extract_api_key(&headers)?;
1377+
1378+
// Verify API key
1379+
let is_valid = state.db_pool.verify_api_key(&api_key).await?;
1380+
if !is_valid {
1381+
return Err(AppError::unauthorized(
1382+
"Your API key is either invalid or does not have correct permission",
1383+
));
1384+
}
1385+
1386+
state
1387+
.db_pool
1388+
.update_episode_duration(request.episode_id, request.new_duration, request.is_youtube)
1389+
.await?;
1390+
Ok(Json(
1391+
serde_json::json!({"detail": format!("Episode duration updated to {}", request.new_duration)}),
1392+
))
1393+
}
1394+
13641395
// Request for mark_episode_completed - matches Python MarkEpisodeCompletedData
13651396
#[derive(Deserialize)]
13661397
pub struct MarkEpisodeCompletedRequest {

rust-api/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ fn create_data_routes() -> Router<AppState> {
225225
.route("/get_play_episode_details", post(handlers::podcasts::get_play_episode_details))
226226
.route("/fetch_podcasting_2_pod_data", get(handlers::podcasts::fetch_podcasting_2_pod_data))
227227
.route("/mark_episode_completed", post(handlers::podcasts::mark_episode_completed))
228+
.route("/update_episode_duration", post(handlers::podcasts::update_episode_duration))
228229
// Bulk episode operations
229230
.route("/bulk_mark_episodes_completed", post(handlers::episodes::bulk_mark_episodes_completed))
230231
.route("/bulk_save_episodes", post(handlers::episodes::bulk_save_episodes))

web/src/components/audio.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use crate::requests::pod_req::{
1111
call_get_auto_skip_times, call_get_episode_id, call_get_play_episode_details,
1212
call_get_podcast_id_from_ep, call_get_queued_episodes, call_increment_listen_time,
1313
call_increment_played, call_mark_episode_completed, call_queue_episode,
14-
call_record_listen_duration, call_remove_queued_episode, HistoryAddRequest,
15-
MarkEpisodeCompletedRequest, QueuePodcastRequest, RecordListenDurationRequest,
14+
call_record_listen_duration, call_remove_queued_episode, call_update_episode_duration, HistoryAddRequest,
15+
MarkEpisodeCompletedRequest, QueuePodcastRequest, RecordListenDurationRequest, UpdateEpisodeDurationRequest
1616
};
1717
use gloo_timers::callback::Interval;
1818
use js_sys::Array;
@@ -1994,8 +1994,17 @@ pub fn on_play_click(
19941994
let actual_duration_sec = get_actual_duration(&src_for_analysis).await;
19951995

19961996
// Use the actual duration if available, otherwise fall back to provided duration
1997-
let final_duration_sec =
1998-
actual_duration_sec.unwrap_or(episode_duration_for_wasm as f64);
1997+
let final_duration_sec = actual_duration_sec.unwrap_or(episode_duration_for_wasm as f64);
1998+
1999+
// Set actual duration in db
2000+
if (final_duration_sec as i32) != episode_duration_for_wasm {
2001+
let req = UpdateEpisodeDurationRequest {
2002+
episode_id,
2003+
new_duration: final_duration_sec as i32,
2004+
is_youtube: episode_is_youtube,
2005+
};
2006+
call_update_episode_duration(&server_name_for_player, &Some(api_key_for_player.clone()), &req).await;
2007+
}
19992008

20002009
web_sys::console::log_1(&JsValue::from_str(&format!(
20012010
"Original duration: {}s, Actual duration: {}s",

web/src/components/episode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ pub fn epsiode() -> Html {
17561756
// Before creating the play toggle handler, add this:
17571757
let listen_duration_percentage = if let Some(listen_duration) = episode.episode.listenduration {
17581758
if episode.episode.episodeduration > 0 {
1759-
(listen_duration as f64 / episode.episode.episodeduration as f64) * 100.0
1759+
((listen_duration as f64 / episode.episode.episodeduration as f64) * 100.0).min(100.0)
17601760
} else {
17611761
0.0
17621762
}

web/src/requests/pod_req.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,48 @@ pub async fn call_check_youtube_channel(
33693369
}
33703370
}
33713371

3372+
#[derive(Serialize, Deserialize, Debug)]
3373+
pub struct UpdateEpisodeDurationRequest {
3374+
pub episode_id: i32,
3375+
pub new_duration: i32,
3376+
pub is_youtube: bool,
3377+
}
3378+
3379+
#[derive(Deserialize, Debug)]
3380+
struct UpdateEpisodeDurationResponse {
3381+
detail: String,
3382+
}
3383+
3384+
pub async fn call_update_episode_duration(
3385+
server_name: &String,
3386+
api_key: &Option<String>,
3387+
request_data: &UpdateEpisodeDurationRequest,
3388+
) -> Result<String, Error> {
3389+
let url = format!("{}/api/data/update_episode_duration", server_name);
3390+
let api_key_ref = api_key.as_deref().ok_or_else(|| anyhow::Error::msg("API key is missing"))?;
3391+
3392+
let request_body = serde_json::to_string(request_data).map_err(|e| anyhow::Error::msg(format!("Serialization Error: {}", e)))?;
3393+
3394+
let response = Request::post(&url)
3395+
.header("Api-Key", api_key_ref)
3396+
.header("Content-Type", "application/json")
3397+
.body(request_body)?
3398+
.send()
3399+
.await?;
3400+
3401+
if response.ok() {
3402+
let response_body: UpdateEpisodeDurationResponse = response.json().await.map_err(|e| anyhow::Error::new(e))?;
3403+
Ok(response_body.detail)
3404+
} else {
3405+
let error_text = response.text().await.unwrap_or_else(|_| String::from("Failed to read error message"));
3406+
Err(anyhow::Error::msg(format!(
3407+
"Failed to update episode duration: {} - {}",
3408+
response.status_text(),
3409+
error_text
3410+
)))
3411+
}
3412+
}
3413+
33723414
#[derive(Debug, Clone, Deserialize, PartialEq)]
33733415
pub struct HomePodcast {
33743416
pub podcastid: i32,

0 commit comments

Comments
 (0)