Skip to content

Commit

Permalink
262 auto numbering episodes (#902)
Browse files Browse the repository at this point in the history
* Added settings for podcasts.

* Added basic podcast level settings.

* Added basic podcast level settings.

* Fixed episode numbering

* Fixed clippy
  • Loading branch information
SamTV12345 authored Aug 28, 2024
1 parent 48001a1 commit c55171d
Show file tree
Hide file tree
Showing 36 changed files with 783 additions and 130 deletions.
2 changes: 0 additions & 2 deletions migrations/2023-12-28-114101_user_api_key/down.sql

This file was deleted.

2 changes: 0 additions & 2 deletions migrations/2023-12-28-114101_user_api_key/up.sql

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE podcasts DROP COLUMN episode_numbering;
DROP TABLE podcast_settings;
21 changes: 21 additions & 0 deletions migrations/postgres/2024-08-25-170551_episode_numbering/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Your SQL goes here

ALTER TABLE podcast_episodes ADD COLUMN episode_numbering_processed BOOLEAN NOT NULL DEFAULT FALSE;
CREATE TABLE podcast_settings (
podcast_id INTEGER PRIMARY KEY NOT NULL,
episode_numbering BOOLEAN NOT NULL DEFAULT FALSE,
auto_download BOOLEAN NOT NULL DEFAULT FALSE,
auto_update BOOLEAN NOT NULL DEFAULT TRUE,
auto_cleanup BOOLEAN NOT NULL DEFAULT FALSE,
auto_cleanup_days INTEGER NOT NULL DEFAULT -1,
replace_invalid_characters BOOLEAN DEFAULT TRUE NOT NULL,
use_existing_filename BOOLEAN DEFAULT FALSE NOT NULL,
replacement_strategy TEXT CHECK(replacement_strategy IN
('replace-with-dash-and-underscore', 'remove', 'replace-with-dash')) NOT NULL DEFAULT
'replace-with-dash-and-underscore',
episode_format TEXT NOT NULL DEFAULT '{}',
podcast_format TEXT NOT NULL DEFAULT '{}',
direct_paths BOOLEAN NOT NULL DEFAULT FALSE,
activated BOOLEAN NOT NULL DEFAULT FALSE,
podcast_prefill INTEGER NOT NULL DEFAULT 0
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE podcast_episodes DROP COLUMN episode_numbering_processed;
DROP TABLE IF EXISTS podcast_settings;
21 changes: 21 additions & 0 deletions migrations/sqlite/2024-08-25-170551_episode_numbering/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Your SQL goes here

ALTER TABLE podcast_episodes ADD COLUMN episode_numbering_processed BOOLEAN NOT NULL DEFAULT FALSE;
CREATE TABLE podcast_settings (
podcast_id INTEGER PRIMARY KEY NOT NULL,
episode_numbering BOOLEAN NOT NULL DEFAULT FALSE,
auto_download BOOLEAN NOT NULL DEFAULT FALSE,
auto_update BOOLEAN NOT NULL DEFAULT TRUE,
auto_cleanup BOOLEAN NOT NULL DEFAULT FALSE,
auto_cleanup_days INTEGER NOT NULL DEFAULT -1,
replace_invalid_characters BOOLEAN DEFAULT TRUE NOT NULL,
use_existing_filename BOOLEAN DEFAULT FALSE NOT NULL,
replacement_strategy TEXT CHECK(replacement_strategy IN
('replace-with-dash-and-underscore', 'remove', 'replace-with-dash')) NOT NULL DEFAULT
'replace-with-dash-and-underscore',
episode_format TEXT NOT NULL DEFAULT '{}',
podcast_format TEXT NOT NULL DEFAULT '{}',
direct_paths BOOLEAN NOT NULL DEFAULT FALSE,
activated BOOLEAN NOT NULL DEFAULT FALSE,
podcast_prefill INTEGER NOT NULL DEFAULT 0
);
57 changes: 55 additions & 2 deletions src/controllers/podcast_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ pub async fn download_podcast(
let mut podcast_service = PodcastService::new();
match podcast_service.refresh_podcast(
podcast.clone(),
lobby,
lobby.clone(),
conn.get().map_err(map_r2d2_error).unwrap().deref_mut(),
) {
Ok(_) => {
Expand All @@ -534,7 +534,20 @@ pub async fn download_podcast(
log::error!("Error refreshing podcast: {}", e);
}
}

let download = podcast_service.schedule_episode_download(
podcast.clone(),
Some(lobby),
conn.get().map_err(map_r2d2_error).unwrap().deref_mut(),
);

if download.is_err() {
log::error!("Error downloading podcast: {}", download.err().unwrap());
}
});



Ok(HttpResponse::Ok().json("Refreshing podcast"))
}

Expand Down Expand Up @@ -707,6 +720,7 @@ use utoipa::ToSchema;

use crate::controllers::podcast_episode_controller::EpisodeFormatDto;
use crate::controllers::websocket_controller::RSSAPiKey;
use crate::models::podcast_settings::PodcastSetting;
use crate::models::settings::Setting;
use crate::utils::environment_variables::is_env_var_present_and_true;

Expand Down Expand Up @@ -844,6 +858,45 @@ pub(crate) async fn proxy_podcast(
Ok(client_resp.streaming(res.bytes_stream()))
}


#[put("/podcasts/{id}/settings")]
pub async fn update_podcast_settings(
id: Path<i32>,
settings: Json<PodcastSetting>,
conn: Data<DbPool>,
requester: Option<web::ReqData<User>>,
) -> Result<HttpResponse, CustomError> {
if !requester.unwrap().is_privileged_user() {
return Err(CustomError::Forbidden);
}

let id_num = id.into_inner();
let mut conn = conn.get().map_err(map_r2d2_error)?;
let mut settings = settings.into_inner();
settings.podcast_id = id_num;
let updated_podcast = PodcastSetting::update_settings(&settings, &mut conn)?;

Ok(HttpResponse::Ok().json(updated_podcast))
}


#[get("/podcasts/{id}/settings")]
pub async fn get_podcast_settings(
id: Path<i32>,
conn: Data<DbPool>,
requester: Option<web::ReqData<User>>,
) -> Result<HttpResponse, CustomError> {
if !requester.unwrap().is_privileged_user() {
return Err(CustomError::Forbidden);
}

let id_num = id.into_inner();
let mut conn = conn.get().map_err(map_r2d2_error)?;
let settings = PodcastSetting::get_settings(&mut conn, id_num)?;

Ok(HttpResponse::Ok().json(settings))
}

#[post("/podcasts/formatting")]
pub async fn retrieve_podcast_sample_format(
sample_string: Json<EpisodeFormatDto>,
Expand All @@ -870,7 +923,7 @@ pub async fn retrieve_podcast_sample_format(
podcast_format: sample_string.0.content,
direct_paths: true,
};
let result = perform_podcast_variable_replacement(settings, podcast);
let result = perform_podcast_variable_replacement(settings, podcast, None);

match result {
Ok(v) => Ok(HttpResponse::Ok().json(v)),
Expand Down
3 changes: 2 additions & 1 deletion src/controllers/podcast_episode_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ pub async fn retrieve_episode_sample_format(
deleted: false,
file_episode_path: None,
file_image_path: None,
episode_numbering_processed: false,
};
let settings = Setting {
id: 0,
Expand All @@ -263,7 +264,7 @@ pub async fn retrieve_episode_sample_format(
podcast_format: "test".to_string(),
direct_paths: true,
};
let result = perform_episode_variable_replacement(settings, episode);
let result = perform_episode_variable_replacement(settings, episode, None);

match result {
Ok(v) => Ok(HttpResponse::Ok().json(v)),
Expand Down
43 changes: 21 additions & 22 deletions src/dbconfig/schemas/sqlite/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ diesel::table! {
deleted -> Bool,
file_episode_path -> Nullable<Text>,
file_image_path -> Nullable<Text>,
episode_numbering_processed -> Bool,
}
}

diesel::table! {
podcast_settings (podcast_id) {
podcast_id -> Integer,
episode_numbering -> Bool,
auto_download -> Bool,
auto_update -> Bool,
auto_cleanup -> Bool,
auto_cleanup_days -> Integer,
replace_invalid_characters -> Bool,
use_existing_filename -> Bool,
replacement_strategy -> Text,
episode_format -> Text,
podcast_format -> Text,
direct_paths -> Bool,
activated -> Bool,
podcast_prefill -> Integer,
}
}

Expand Down Expand Up @@ -158,24 +178,6 @@ diesel::table! {
}
}

diesel::table! {
tags (id) {
id -> Text,
name -> Text,
username -> Text,
description -> Nullable<Text>,
created_at -> Timestamp,
color -> Text,
}
}

diesel::table! {
tags_podcasts (tag_id, podcast_id) {
tag_id -> Text,
podcast_id -> Integer,
}
}

diesel::table! {
users (id) {
id -> Integer,
Expand All @@ -192,8 +194,6 @@ diesel::joinable!(favorites -> podcasts (podcast_id));
diesel::joinable!(playlist_items -> playlists (playlist_id));
diesel::joinable!(playlist_items -> podcast_episodes (episode));
diesel::joinable!(podcast_episodes -> podcasts (podcast_id));
diesel::joinable!(tags_podcasts -> podcasts (podcast_id));
diesel::joinable!(tags_podcasts -> tags (tag_id));

diesel::allow_tables_to_appear_in_same_query!(
devices,
Expand All @@ -205,11 +205,10 @@ diesel::allow_tables_to_appear_in_same_query!(
playlist_items,
playlists,
podcast_episodes,
podcast_settings,
podcasts,
sessions,
settings,
subscriptions,
tags,
tags_podcasts,
users,
);
8 changes: 3 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,7 @@ use crate::controllers::playlist_controller::{
add_playlist, delete_playlist_by_id, delete_playlist_item, get_all_playlists,
get_playlist_by_id, update_playlist,
};
use crate::controllers::podcast_controller::{
add_podcast, add_podcast_by_feed, delete_podcast, find_all_podcasts, find_podcast,
find_podcast_by_id, get_filter, proxy_podcast, refresh_all_podcasts,
retrieve_podcast_sample_format, search_podcasts,
};
use crate::controllers::podcast_controller::{add_podcast, add_podcast_by_feed, delete_podcast, find_all_podcasts, find_podcast, find_podcast_by_id, get_filter, get_podcast_settings, proxy_podcast, refresh_all_podcasts, retrieve_podcast_sample_format, search_podcasts, update_podcast_settings};
use crate::controllers::podcast_controller::{
add_podcast_from_podindex, download_podcast, favorite_podcast, get_favored_podcasts,
import_podcasts_from_opml, query_for_podcast, update_active_podcast,
Expand Down Expand Up @@ -458,6 +454,8 @@ fn get_private_api() -> Scope<
.service(delete_podcast_episode_locally)
.service(retrieve_episode_sample_format)
.service(retrieve_podcast_sample_format)
.service(update_podcast_settings)
.service(get_podcast_settings)
}

pub fn config_secure_user_management(cfg: &mut web::ServiceConfig) {
Expand Down
1 change: 1 addition & 0 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ pub mod subscription;
pub mod subscription_changes_from_client;
pub mod user;
pub mod web_socket_message;
pub mod podcast_settings;
52 changes: 45 additions & 7 deletions src/models/podcast_episode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::constants::inner_constants::DEFAULT_IMAGE_URL;
use crate::dbconfig::schema::*;
use crate::dbconfig::DBType;
use crate::models::episode::Episode;
use crate::models::playlist_item::PlaylistItem;
use crate::models::podcasts::Podcast;
Expand Down Expand Up @@ -72,6 +73,8 @@ pub struct PodcastEpisode {
pub(crate) file_episode_path: Option<String>,
#[diesel(sql_type = Nullable<Text>)]
pub(crate) file_image_path: Option<String>,
#[diesel(sql_type = Bool)]
pub (crate) episode_numbering_processed : bool,
}

impl PodcastEpisode {
Expand All @@ -94,6 +97,24 @@ impl PodcastEpisode {
Ok(found_podcast_episode)
}

pub fn get_position_of_episode(
timestamp: &str,
pid: i32,
conn: &mut DBType,
) -> Result<usize, CustomError> {
use crate::dbconfig::schema::podcast_episodes::dsl::*;

let result = diesel::QueryDsl::order(
podcast_episodes
.filter(podcast_id.eq(pid))
.filter(date_of_recording.le(timestamp)),
date_of_recording.desc(),
)
.execute(conn)
.map_err(map_db_error)?;
Ok(result)
}

pub fn get_podcast_episode_by_id(
conn: &mut DbConnection,
podcas_episode_id_to_be_found: &str,
Expand Down Expand Up @@ -175,13 +196,16 @@ impl PodcastEpisode {
// Sometimes it occurs that day of the week and date are wrong. This just
// takes the date and parses it
let date_without_weekday = date[5..].to_string();
DateTime::parse_from_str(&date_without_weekday, "%d %b %Y \
%H:%M:%S %z")
.map(|date| {
let conv_date = date.with_timezone(&Utc);
inserted_date = conv_date.to_rfc3339()
})
.expect("Error parsing date");
DateTime::parse_from_str(
&date_without_weekday,
"%d %b %Y \
%H:%M:%S %z",
)
.map(|date| {
let conv_date = date.with_timezone(&Utc);
inserted_date = conv_date.to_rfc3339()
})
.expect("Error parsing date");
}
}
}
Expand Down Expand Up @@ -432,11 +456,13 @@ impl PodcastEpisode {
pub fn get_podcast_episodes_older_than_days(
days: i32,
conn: &mut DbConnection,
podcast_id_to_search: i32,
) -> Vec<PodcastEpisode> {
use crate::dbconfig::schema::podcast_episodes::dsl::*;

podcast_episodes
.filter(download_time.lt(Utc::now().naive_utc() - Duration::days(days as i64)))
.filter(podcast_id.eq(podcast_id_to_search))
.load::<PodcastEpisode>(conn)
.expect("Error loading podcast episode by id")
}
Expand Down Expand Up @@ -540,4 +566,16 @@ impl PodcastEpisode {
.load::<PodcastEpisode>(conn)
.map_err(map_db_error)
}

pub fn update_episode_numbering_processed(conn: &mut DBType, processed: bool,
episode_id_to_update: &str) {
use crate::dbconfig::schema::podcast_episodes::dsl::*;
use crate::dbconfig::schema::podcast_episodes::dsl::episode_numbering_processed as episode_numbering_processed_column;
use crate::dbconfig::schema::podcast_episodes::dsl::podcast_episodes as dsl_podcast_episodes;
diesel::update(dsl_podcast_episodes)
.set(episode_numbering_processed_column.eq(processed))
.filter(episode_id.eq(episode_id_to_update))
.execute(conn)
.expect("Error updating episode numbering processed");
}
}
Loading

0 comments on commit c55171d

Please sign in to comment.