Skip to content

Commit 90f77f3

Browse files
authored
Better manga tracking (#921)
* refactor(frontend): do not send all data in action * build(backend): upgrade schematic deps * feat(frontend): add checkbox for podcast all episodes before * chore(frontend): remove useless attribute from data * fix(backend): allow progress update when provider watched on changes Signed-off-by: Diptesh Choudhuri <ignisda2001@gmail.com> * fix(backend): set updated_at only if progress changes * refactor(frontend): change name of attribute * chore(frontend): set progress in backend * feat(database): remove outdated columns from user * fix(frontend): get updating podcast progress working * refactor(frontend): eliminate useless parameters * refactor(backend): move location of entity * refactor(backend): move util to service method * refactor(backend): move method into model file * refactor(backend): move more stuff out of miscellaneous mod * refactor(backend): make the mod file of miscellenous empty * refactor(backend): remove module and move into separate file * refactor(backend): remove useless variable * fix(frontend): remove useless code * feat(frontend): get show progress update working * feat(frontend): use new schema for update * Revert "feat(frontend): use new schema for update" This reverts commit 4b2ba00. * chore(frontend): remove duplicated code * fix(backend): remove useless `and_then` invocation * fix(backend): do not calculate next_entry from `is_finished` * fix(frontend): remove useless if checks * fix(frontend): allow setting manga volume number * feat(frontend): get anime progress working * feat(backend): get next volume for manga * refactor(frontend): extract constant to scope * feat(frontend): show next entry for manga * fix(frontend): make episode field non nullable * fix(backend): fallback when anilist titles not available * feat(frontend): throw error when both inputs are given * fix(frontend): make UI more coherent * feat(frontend): preliminary if check * docs: add timezone to both containers * fix(frontend): display correct value of next entry * refactor(frontend): remove extra nesting * fix(frontend): make conditionals more concise * fix(frontend): throw response instead of error * refactor(backend): use new default * build(backend): bump versions Signed-off-by: Diptesh Choudhuri <ignisda2001@gmail.com> * build(ts): upgrade dependencies * fix(frontend): better error message * feat(frontend): handle manga volumes and chapter updates * fix(frontend): change variant of btns * fix(frontend): change variant of btns --------- Signed-off-by: Diptesh Choudhuri <ignisda2001@gmail.com>
1 parent 9b7c801 commit 90f77f3

40 files changed

+1114
-1109
lines changed

Cargo.lock

+214-214
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ resolver = "2"
44

55
[workspace.dependencies]
66
anyhow = "=1.0.82"
7-
async-graphql = { version = "=7.0.6", features = [
7+
async-graphql = { version = "=7.0.7", features = [
88
"chrono",
99
"decimal",
1010
"log",
@@ -13,7 +13,7 @@ async-graphql = { version = "=7.0.6", features = [
1313
chrono = "=0.4.38"
1414
dotenvy_macro = "=0.15.7"
1515
nanoid = "=0.4.0"
16-
schematic = { version = "=0.16.4", features = [
16+
schematic = { version = "=0.16.6", features = [
1717
"config",
1818
"json",
1919
"schema",
@@ -37,7 +37,7 @@ sea-orm = { version = "=1.0.0-rc.5", features = [
3737
"with-uuid",
3838
], default-features = false }
3939
sea-orm-migration = "=1.0.0-rc.5"
40-
serde = { version = "=1.0.202", features = ["derive"] }
41-
serde_json = "=1.0.117"
40+
serde = { version = "=1.0.204", features = ["derive"] }
41+
serde_json = "=1.0.120"
4242
strum = { version = "=0.26.2", features = ["derive"] }
4343
tracing = { version = "=0.1.40", features = ["attributes"] }

apps/backend/Cargo.toml

+8-8
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ anyhow = { workspace = true }
1010
apalis = { version = "=0.5.3", features = ["cron", "limit"] }
1111
argon2 = "=0.6.0-pre.0"
1212
async-graphql = { workspace = true }
13-
async-graphql-axum = "=7.0.6"
13+
async-graphql-axum = "=7.0.7"
1414
async-trait = "=0.1.81"
15-
aws-sdk-s3 = { version = "=1.40.0", features = ["behavior-version-latest"] }
15+
aws-sdk-s3 = { version = "=1.42.0", features = ["behavior-version-latest"] }
1616
axum = { version = "=0.7.5", features = ["macros", "multipart"] }
1717
boilermates = "=0.3.0"
18-
cached = { version = "=0.52.0", features = ["disk_store"] }
18+
cached = { version = "=0.53.1", features = ["disk_store"] }
1919
chrono = { workspace = true }
2020
chrono-tz = "=0.9.0"
2121
compile-time = "=0.2.0"
@@ -63,21 +63,21 @@ reqwest = { git = "https://github.com/thomasqueirozb/reqwest", branch = "base_ur
6363
], default-features = false }
6464
rs-utils = { path = "../../libs/rs-utils" }
6565
rust_decimal = "=1.35.0"
66-
rust_decimal_macros = "=1.34.2"
66+
rust_decimal_macros = "=1.35.0"
6767
rust_iso3166 = "=0.1.13"
6868
schematic = { workspace = true }
69-
scraper = "=0.19.0"
69+
scraper = "=0.19.1"
7070
sea-orm = { workspace = true }
7171
sea-orm-migration = { workspace = true }
72-
sea-query = "=0.31.0-rc.8"
72+
sea-query = "=0.31.0-rc.9"
7373
serde = { workspace = true }
7474
serde_json = { workspace = true }
75-
serde_with = { version = "=3.8.3", features = ["chrono_0_4"] }
75+
serde_with = { version = "=3.9.0", features = ["chrono_0_4"] }
7676
serde-xml-rs = "=0.6.0"
7777
slug = "=0.1.5"
7878
strum = { workspace = true }
7979
struson = { version = "=0.5.0", features = ["serde"] }
80-
tokio = { version = "=1.38.0", features = ["full"] }
80+
tokio = { version = "=1.38.1", features = ["full"] }
8181
tokio-util = { version = "=0.7.11", features = ["codec"] }
8282
tower = { version = "=0.4.13", features = ["buffer"] }
8383
tower-http = { version = "=0.5.2", features = ["catch-panic", "cors", "trace"] }

apps/backend/src/background.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
exporter::ExporterService,
1212
fitness::resolver::ExerciseService,
1313
importer::{DeployImportJobInput, ImporterService},
14-
miscellaneous::resolver::MiscellaneousService,
14+
miscellaneous::MiscellaneousService,
1515
models::{
1616
fitness::Exercise,
1717
media::{CommitMediaInput, ProgressUpdateInput, ReviewPostedEvent},

apps/backend/src/entities/collection.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use sea_orm::entity::prelude::*;
77
use sea_orm::ActiveValue;
88
use serde::{Deserialize, Serialize};
99

10-
use crate::miscellaneous::CollectionExtraInformation;
10+
use crate::models::CollectionExtraInformation;
1111

1212
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, SimpleObject)]
1313
#[sea_orm(table_name = "collection")]

apps/backend/src/entities/exercise.rs

+3-33
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use database::{
88
ExerciseEquipment, ExerciseForce, ExerciseLevel, ExerciseLot, ExerciseMechanic, ExerciseMuscle,
99
ExerciseSource,
1010
};
11-
use sea_orm::{entity::prelude::*, FromQueryResult};
11+
use sea_orm::entity::prelude::*;
1212
use serde::{Deserialize, Serialize};
1313

1414
use crate::{
1515
file_storage::FileStorageService, models::fitness::ExerciseAttributes,
16-
traits::GraphqlRepresentation, utils::get_stored_asset,
16+
traits::GraphqlRepresentation,
1717
};
1818

1919
#[derive(
@@ -58,43 +58,13 @@ impl GraphqlRepresentation for Model {
5858
let mut converted_exercise = self.clone();
5959
let mut images = vec![];
6060
for image in self.attributes.internal_images.iter() {
61-
images.push(get_stored_asset(image.clone(), file_storage_service).await);
61+
images.push(file_storage_service.get_stored_asset(image.clone()).await);
6262
}
6363
converted_exercise.attributes.images = images;
6464
Ok(converted_exercise)
6565
}
6666
}
6767

68-
#[derive(Clone, Debug, Deserialize, SimpleObject, FromQueryResult)]
69-
pub struct ExerciseListItem {
70-
pub lot: ExerciseLot,
71-
pub id: String,
72-
#[graphql(skip)]
73-
pub attributes: ExerciseAttributes,
74-
pub num_times_interacted: Option<i32>,
75-
pub last_updated_on: Option<DateTimeUtc>,
76-
pub muscle: Option<ExerciseMuscle>,
77-
pub image: Option<String>,
78-
#[graphql(skip)]
79-
pub muscles: Vec<ExerciseMuscle>,
80-
}
81-
82-
#[async_trait]
83-
impl GraphqlRepresentation for ExerciseListItem {
84-
async fn graphql_representation(
85-
self,
86-
file_storage_service: &Arc<FileStorageService>,
87-
) -> Result<Self> {
88-
let mut converted_exercise = self.clone();
89-
if let Some(img) = self.attributes.internal_images.first() {
90-
converted_exercise.image =
91-
Some(get_stored_asset(img.clone(), file_storage_service).await);
92-
}
93-
converted_exercise.muscle = self.muscles.first().cloned();
94-
Ok(converted_exercise)
95-
}
96-
}
97-
9868
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
9969
pub enum Relation {
10070
#[sea_orm(has_many = "super::collection_to_entity::Entity")]

apps/backend/src/exporter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use tokio_util::codec::{BytesCodec, FramedRead};
1717

1818
use crate::{
1919
background::ApplicationJob, file_storage::FileStorageService,
20-
fitness::resolver::ExerciseService, miscellaneous::resolver::MiscellaneousService,
21-
models::ExportItem, traits::AuthProvider, utils::TEMP_DIR,
20+
fitness::resolver::ExerciseService, miscellaneous::MiscellaneousService, models::ExportItem,
21+
traits::AuthProvider, utils::TEMP_DIR,
2222
};
2323

2424
#[derive(Debug, Serialize, Deserialize, SimpleObject, Clone)]

apps/backend/src/file_storage.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use aws_sdk_s3::presigning::PresigningConfig;
44
use chrono::Duration;
55
use nanoid::nanoid;
66

7+
use crate::models::StoredUrl;
8+
79
#[derive(Debug)]
810
pub struct FileStorageService {
911
s3_client: aws_sdk_s3::Client,
@@ -104,4 +106,11 @@ impl FileStorageService {
104106
.metadata
105107
.unwrap()
106108
}
109+
110+
pub async fn get_stored_asset(&self, url: StoredUrl) -> String {
111+
match url {
112+
StoredUrl::Url(u) => u,
113+
StoredUrl::S3(u) => self.get_presigned_url(u).await,
114+
}
115+
}
107116
}

apps/backend/src/fitness/resolver.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,19 @@ use struson::writer::{JsonStreamWriter, JsonWriter};
2020
use crate::{
2121
background::ApplicationJob,
2222
entities::{
23-
collection, collection_to_entity,
24-
exercise::{self, ExerciseListItem},
23+
collection, collection_to_entity, exercise,
2524
prelude::{CollectionToEntity, Exercise, UserMeasurement, UserToEntity, Workout},
2625
user_measurement, user_to_entity, workout,
2726
},
2827
file_storage::FileStorageService,
29-
miscellaneous::DefaultCollection,
3028
models::{
3129
fitness::{
32-
Exercise as GithubExercise, ExerciseAttributes, ExerciseCategory,
30+
Exercise as GithubExercise, ExerciseAttributes, ExerciseCategory, ExerciseListItem,
3331
GithubExerciseAttributes, UserExerciseInput, UserToExerciseHistoryExtraInformation,
34-
UserWorkoutInput, UserWorkoutSetRecord, WorkoutListItem,
32+
UserWorkoutInput, UserWorkoutSetRecord,
3533
},
36-
ChangeCollectionToEntityInput, SearchDetails, SearchInput, SearchResults, StoredUrl,
34+
ChangeCollectionToEntityInput, DefaultCollection, SearchDetails, SearchInput,
35+
SearchResults, StoredUrl,
3736
},
3837
traits::{AuthProvider, GraphqlRepresentation},
3938
utils::{add_entity_to_collection, entity_in_collections, ilike_sql, user_by_id},
@@ -145,7 +144,7 @@ impl ExerciseQuery {
145144
&self,
146145
gql_ctx: &Context<'_>,
147146
input: SearchInput,
148-
) -> Result<SearchResults<WorkoutListItem>> {
147+
) -> Result<SearchResults<workout::Model>> {
149148
let service = gql_ctx.data_unchecked::<Arc<ExerciseService>>();
150149
let user_id = self.user_id_from_ctx(gql_ctx).await?;
151150
service.user_workouts_list(user_id, input).await
@@ -407,7 +406,7 @@ impl ExerciseService {
407406
&self,
408407
user_id: String,
409408
input: SearchInput,
410-
) -> Result<SearchResults<WorkoutListItem>> {
409+
) -> Result<SearchResults<workout::Model>> {
411410
let page = input.page.unwrap_or(1);
412411
let query = Workout::find()
413412
.filter(workout::Column::UserId.eq(user_id))
@@ -417,9 +416,7 @@ impl ExerciseService {
417416
.order_by_desc(workout::Column::EndTime);
418417
let total = query.clone().count(&self.db).await?;
419418
let total: i32 = total.try_into().unwrap();
420-
let data = query
421-
.into_partial_model::<WorkoutListItem>()
422-
.paginate(&self.db, self.config.frontend.page_size.try_into().unwrap());
419+
let data = query.paginate(&self.db, self.config.frontend.page_size.try_into().unwrap());
423420
let items = data.fetch_page((page - 1).try_into().unwrap()).await?;
424421
let next_page = if total - (page * self.config.frontend.page_size) > 0 {
425422
Some(page + 1)

apps/backend/src/graphql.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
exporter::{ExporterMutation, ExporterQuery},
55
fitness::resolver::{ExerciseMutation, ExerciseQuery},
66
importer::{ImporterMutation, ImporterQuery},
7-
miscellaneous::resolver::{MiscellaneousMutation, MiscellaneousQuery},
7+
miscellaneous::{MiscellaneousMutation, MiscellaneousQuery},
88
utils::AppServices,
99
};
1010

apps/backend/src/importer/audiobookshelf.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ use serde_json::json;
1313
use crate::{
1414
entities::metadata,
1515
importer::{ImportFailStep, ImportFailedItem, ImportResult},
16-
miscellaneous::{audiobookshelf_models, itunes_podcast_episode_by_name},
17-
models::media::{CommitMediaInput, ImportOrExportMediaItem, ImportOrExportMediaItemSeen},
16+
models::{
17+
audiobookshelf_models,
18+
media::{CommitMediaInput, ImportOrExportMediaItem, ImportOrExportMediaItemSeen},
19+
},
1820
providers::google_books::GoogleBooksService,
1921
utils::get_base_http_client,
2022
};
@@ -115,8 +117,9 @@ where
115117
..Default::default()
116118
})
117119
.await?;
118-
if let Some(pe) =
119-
itunes_podcast_episode_by_name(&episode.title, podcast)
120+
if let Some(pe) = podcast
121+
.podcast_specifics
122+
.and_then(|p| p.episode_by_name(&episode.title))
120123
{
121124
to_return.push(pe);
122125
}

apps/backend/src/importer/igdb.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use itertools::Itertools;
55
use rust_decimal_macros::dec;
66
use serde::Deserialize;
77

8-
use crate::{
9-
miscellaneous::DefaultCollection,
10-
models::media::{ImportOrExportMediaItem, ImportOrExportMediaItemSeen},
8+
use crate::models::{
9+
media::{ImportOrExportMediaItem, ImportOrExportMediaItemSeen},
10+
DefaultCollection,
1111
};
1212

1313
use super::{DeployIgdbImportInput, ImportFailStep, ImportFailedItem, ImportResult};

apps/backend/src/importer/imdb.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use serde::Deserialize;
66

77
use crate::{
88
importer::{DeployGenericCsvImportInput, ImportFailStep, ImportFailedItem, ImportResult},
9-
miscellaneous::DefaultCollection,
10-
models::media::ImportOrExportMediaItem,
9+
models::{media::ImportOrExportMediaItem, DefaultCollection},
1110
providers::tmdb::NonMediaTmdbService,
1211
};
1312

apps/backend/src/importer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
background::ApplicationJob,
1717
entities::{import_report, prelude::ImportReport, user_measurement},
1818
fitness::resolver::ExerciseService,
19-
miscellaneous::resolver::MiscellaneousService,
19+
miscellaneous::MiscellaneousService,
2020
models::{
2121
fitness::UserWorkoutInput,
2222
media::{

apps/backend/src/importer/movary.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use crate::{
1212
DeployMovaryImportInput, ImportFailStep, ImportFailedItem, ImportOrExportMediaItem,
1313
ImportResult,
1414
},
15-
miscellaneous::DefaultCollection,
16-
models::media::{
17-
ImportOrExportItemRating, ImportOrExportItemReview, ImportOrExportMediaItemSeen,
15+
models::{
16+
media::{ImportOrExportItemRating, ImportOrExportItemReview, ImportOrExportMediaItemSeen},
17+
DefaultCollection,
1818
},
1919
};
2020

apps/backend/src/integrations.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use serde::{Deserialize, Serialize};
1313

1414
use crate::{
1515
entities::{metadata, prelude::Metadata},
16-
miscellaneous::{audiobookshelf_models, itunes_podcast_episode_by_name},
17-
models::media::CommitMediaInput,
16+
models::{audiobookshelf_models, media::CommitMediaInput},
1817
providers::google_books::GoogleBooksService,
1918
utils::{get_base_http_client, ilike_sql},
2019
};
@@ -339,7 +338,10 @@ impl IntegrationService {
339338
})
340339
.await
341340
.unwrap();
342-
match itunes_podcast_episode_by_name(&pe.title, podcast) {
341+
match podcast
342+
.podcast_specifics
343+
.and_then(|p| p.episode_by_name(&pe.title))
344+
{
343345
Some(episode) => (
344346
format!("{}/{}", item.id, pe.id),
345347
itunes_id,

0 commit comments

Comments
 (0)