Repository: IgnisDa/ryot (language: rust)

Issue:
Add Reps_And_Duration for type?
Could you add reps_and_duration and reps_and_duration_and_distance as types? If we're using this to track swimming laps we could use reps as a replacement for laps, then could track duration for the time per lap or total time for that set. We might also want to include distance swam in that as well. Is that a hard addition to make? 


Discussion / hints:
Not very difficult, but I have a few questions.

<img width="863" alt="image" src="https://github.com/user-attachments/assets/21f99c5c-b88e-45e9-9c62-7faba300cc2e" />

What personal best types would be associated with these exercise types? Also what new best types can be calculated for them?
Hmm, I think reps/laps is definitely a thing. Time would be something. Could be time per lap or total time on laps. So best time would likely be shortest time per lap/rep (like total time divided by reps/laps = time per lap if not setting laps as sets or something). Volume/number of laps.
Whats an exercise for reps_and_duration_and_distance?
Laps in a pool could be laps and duration or laps and duration and distance since you could also track distance swam. Running in a track could be the same. Admittedly, I'd use laps and duration more. I'm not much for a track or total distance travelled. 
Makes sense. But I won't have any of the inputs nullable. If you need that, you should create two different exercises.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 884cb8c9b9..f9f59b5602 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1781,6 +1781,7 @@ dependencies = [
  "dependent-models",
  "either",
  "enum-models",
+ "enum_meta",
  "file-storage-service",
  "fitness-models",
  "importer-models",
@@ -2146,6 +2147,7 @@ name = "enum-models"
 version = "0.1.0"
 dependencies = [
  "async-graphql",
+ "enum_meta",
  "schematic",
  "sea-orm",
  "sea-orm-migration",
@@ -6351,6 +6353,7 @@ dependencies = [
  "config",
  "dependent-models",
  "enum-models",
+ "enum_meta",
  "env-utils",
  "file-storage-service",
  "isolang",
diff --git a/apps/frontend/app/components/fitness.tsx b/apps/frontend/app/components/fitness.tsx
index 611adc0e9b..8e4a7f7645 100644
--- a/apps/frontend/app/components/fitness.tsx
+++ b/apps/frontend/app/components/fitness.tsx
@@ -65,6 +65,11 @@ export const getSetStatisticsTextToDisplay = (
 	unit: UserUnitSystem,
 ) => {
 	return match(lot)
+		.with(ExerciseLot.Reps, () => [`${statistic.reps} reps`, undefined])
+		.with(ExerciseLot.RepsAndDuration, () => [
+			`${statistic.reps} reps for ${Number(statistic.duration).toFixed(2)} min`,
+			undefined,
+		])
 		.with(ExerciseLot.DistanceAndDuration, () => [
 			`${displayDistanceWithUnit(unit, statistic.distance)} for ${Number(
 				statistic.duration,
@@ -75,13 +80,16 @@ export const getSetStatisticsTextToDisplay = (
 			`${Number(statistic.duration).toFixed(2)} min`,
 			undefined,
 		])
-		.with(ExerciseLot.Reps, () => [`${statistic.reps} reps`, undefined])
 		.with(ExerciseLot.RepsAndWeight, () => [
 			statistic.weight && statistic.weight !== "0"
 				? `${displayWeightWithUnit(unit, statistic.weight)} × ${statistic.reps}`
 				: `${statistic.reps} reps`,
 			statistic.oneRm ? `${Number(statistic.oneRm).toFixed(1)} RM` : null,
 		])
+		.with(ExerciseLot.RepsAndDurationAndDistance, () => [
+			`${displayDistanceWithUnit(unit, statistic.distance)} × ${statistic.reps}`,
+			`${Number(statistic.duration).toFixed(2)} min`,
+		])
 		.exhaustive();
 };
 
diff --git a/apps/frontend/app/routes/_dashboard.fitness.$action.tsx b/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
index 680eb98e1a..be122eabfd 100644
--- a/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
+++ b/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
@@ -1461,10 +1461,17 @@ const ExerciseDisplay = (props: {
 
 	const exerciseHistory = userExerciseDetails?.history;
 	const [durationCol, distanceCol, weightCol, repsCol] = match(exercise.lot)
-		.with(ExerciseLot.DistanceAndDuration, () => [true, true, false, false])
+		.with(ExerciseLot.Reps, () => [false, false, false, true])
 		.with(ExerciseLot.Duration, () => [true, false, false, false])
 		.with(ExerciseLot.RepsAndWeight, () => [false, false, true, true])
-		.with(ExerciseLot.Reps, () => [false, false, false, true])
+		.with(ExerciseLot.RepsAndDuration, () => [true, false, false, true])
+		.with(ExerciseLot.DistanceAndDuration, () => [true, true, false, false])
+		.with(ExerciseLot.RepsAndDurationAndDistance, () => [
+			true,
+			true,
+			false,
+			true,
+		])
 		.exhaustive();
 	const toBeDisplayedColumns =
 		[durationCol, distanceCol, weightCol, repsCol].filter(Boolean).length + 1;
@@ -2289,24 +2296,37 @@ const SetDisplay = (props: {
 										variant={set.confirmedAt ? "filled" : "outline"}
 										disabled={
 											!match(exercise.lot)
+												.with(ExerciseLot.Reps, () =>
+													isString(set.statistic.reps),
+												)
+												.with(ExerciseLot.Duration, () =>
+													isString(set.statistic.duration),
+												)
+												.with(
+													ExerciseLot.RepsAndDuration,
+													() =>
+														isString(set.statistic.reps) &&
+														isString(set.statistic.duration),
+												)
 												.with(
 													ExerciseLot.DistanceAndDuration,
 													() =>
 														isString(set.statistic.distance) &&
 														isString(set.statistic.duration),
 												)
-												.with(ExerciseLot.Duration, () =>
-													isString(set.statistic.duration),
-												)
-												.with(ExerciseLot.Reps, () =>
-													isString(set.statistic.reps),
-												)
 												.with(
 													ExerciseLot.RepsAndWeight,
 													() =>
 														isString(set.statistic.reps) &&
 														isString(set.statistic.weight),
 												)
+												.with(
+													ExerciseLot.RepsAndDurationAndDistance,
+													() =>
+														isString(set.statistic.reps) &&
+														isString(set.statistic.duration) &&
+														isString(set.statistic.distance),
+												)
 												.exhaustive()
 										}
 										onClick={async () => {
diff --git a/apps/frontend/app/routes/_dashboard.fitness.exercises.item.$id._index.tsx b/apps/frontend/app/routes/_dashboard.fitness.exercises.item.$id._index.tsx
index df3e45403a..a316395268 100644
--- a/apps/frontend/app/routes/_dashboard.fitness.exercises.item.$id._index.tsx
+++ b/apps/frontend/app/routes/_dashboard.fitness.exercises.item.$id._index.tsx
@@ -531,6 +531,10 @@ export default function Page() {
 														WorkoutSetPersonalBest.Weight,
 														() => stat?.weight,
 													)
+													.with(
+														WorkoutSetPersonalBest.Distance,
+														() => stat?.distance,
+													)
 													.exhaustive();
 												return {
 													name: dayjsLib(h.workoutEndOn).format("DD/MM/YYYY"),
@@ -745,6 +749,9 @@ const DisplayPersonalBest = (props: {
 						displayWeightWithUnit(unitSystem, set.statistic.weight),
 					)
 					.with(WorkoutSetPersonalBest.Pace, () => `${set.statistic.pace}/min`)
+					.with(WorkoutSetPersonalBest.Distance, () =>
+						displayDistanceWithUnit(unitSystem, set.statistic.distance),
+					)
 					.exhaustive()}
 			</Text>
 			<Group>
diff --git a/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx b/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
index b9cf8fffdb..5affe35d99 100644
--- a/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
+++ b/apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
@@ -336,50 +336,46 @@ export default function Page() {
 								<FiltersModalForm />
 							</FiltersModal>
 						</Group>
-						{loaderData.mediaList.list.response.details.total > 0 ? (
-							<>
-								<DisplayListDetailsAndRefresh
-									cacheId={loaderData.mediaList.list.cacheId}
-									total={loaderData.mediaList.list.response.details.total}
-								/>
-								{(loaderData.mediaList?.url.startDateRange ||
-									loaderData.mediaList?.url.endDateRange) &&
-								!coreDetails.isServerKeyValidated ? (
-									<ProRequiredAlert alertText="Ryot Pro is required to filter by dates" />
-								) : (
-									<ApplicationGrid>
-										{loaderData.mediaList.list.response.items.map((item) => {
-											const becItem = {
-												entityId: item,
-												entityLot: EntityLot.Metadata,
-											};
-											const isAdded = bulkEditingCollection.isAdded(becItem);
-											return (
-												<MetadataDisplayItem
-													key={item}
-													metadataId={item}
-													rightLabelHistory
-													topRight={
-														bulkEditingState &&
-														bulkEditingState.data.action === "add" ? (
-															<ActionIcon
-																variant={isAdded ? "filled" : "transparent"}
-																color="green"
-																onClick={() => {
-																	if (isAdded) bulkEditingState.remove(becItem);
-																	else bulkEditingState.add(becItem);
-																}}
-															>
-																<IconCheck size={18} />
-															</ActionIcon>
-														) : undefined
-													}
-												/>
-											);
-										})}
-									</ApplicationGrid>
-								)}
-							</>
+						<DisplayListDetailsAndRefresh
+							cacheId={loaderData.mediaList.list.cacheId}
+							total={loaderData.mediaList.list.response.details.total}
+						/>
+						{(loaderData.mediaList?.url.startDateRange ||
+							loaderData.mediaList?.url.endDateRange) &&
+						!coreDetails.isServerKeyValidated ? (
+							<ProRequiredAlert alertText="Ryot Pro is required to filter by dates" />
+						) : loaderData.mediaList.list.response.details.total > 0 ? (
+							<ApplicationGrid>
+								{loaderData.mediaList.list.response.items.map((item) => {
+									const becItem = {
+										entityId: item,
+										entityLot: EntityLot.Metadata,
+									};
+									const isAdded = bulkEditingCollection.isAdded(becItem);
+									return (
+										<MetadataDisplayItem
+											key={item}
+											metadataId={item}
+											rightLabelHistory
+											topRight={
+												bulkEditingState &&
+												bulkEditingState.data.action === "add" ? (
+													<ActionIcon
+														variant={isAdded ? "filled" : "transparent"}
+														color="green"
+														onClick={() => {
+															if (isAdded) bulkEditingState.remove(becItem);
+															else bulkEditingState.add(becItem);
+														}}
+													>
+														<IconCheck size={18} />
+													</ActionIcon>
+												) : undefined
+											}
+										/>
+									);
+								})}
+							</ApplicationGrid>
 						) : (
 							<Text>You do not have any saved yet</Text>
 						)}
diff --git a/crates/models/common/src/lib.rs b/crates/models/common/src/lib.rs
index af07b21721..0c7e5a40b1 100644
--- a/crates/models/common/src/lib.rs
+++ b/crates/models/common/src/lib.rs
@@ -91,6 +91,7 @@ pub enum DefaultCollection {
 
 meta! {
     DefaultCollection, (Option<Vec<CollectionExtraInformation>>, &'static str);
+
     Watchlist, (None, "Things I want to watch in the future.");
     InProgress, (None, "Media items that I am currently watching.");
     Completed, (None, "Media items that I have completed.");
@@ -109,15 +110,15 @@ meta! {
     Reminders, (Some(
         vec![
             CollectionExtraInformation {
-                name: "Reminder".to_string(),
                 required: Some(true),
+                name: "Reminder".to_string(),
                 lot: CollectionExtraInformationLot::Date,
                 description: "When do you want to be reminded?".to_string(),
                 ..Default::default()
             },
             CollectionExtraInformation {
-                name: "Text".to_string(),
                 required: Some(true),
+                name: "Text".to_string(),
                 lot: CollectionExtraInformationLot::String,
                 description: "What do you want to be reminded about?".to_string(),
                 ..Default::default()
diff --git a/crates/models/enum/Cargo.toml b/crates/models/enum/Cargo.toml
index 69ce2706b2..b7a3c64541 100644
--- a/crates/models/enum/Cargo.toml
+++ b/crates/models/enum/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 async-graphql = { workspace = true }
+enum_meta = { workspace = true }
 schematic = { workspace = true }
 sea-orm = { workspace = true }
 sea-orm-migration = { workspace = true }
diff --git a/crates/models/enum/src/lib.rs b/crates/models/enum/src/lib.rs
index aaa33afc7d..0eda4f7c81 100644
--- a/crates/models/enum/src/lib.rs
+++ b/crates/models/enum/src/lib.rs
@@ -1,4 +1,5 @@
 use async_graphql::Enum;
+use enum_meta::{meta, Meta};
 use schematic::ConfigEnum;
 use sea_orm::{DeriveActiveEnum, EnumIter, FromJsonQueryResult};
 use sea_orm_migration::prelude::*;
@@ -23,8 +24,8 @@ use strum::Display;
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum MediaLot {
@@ -41,26 +42,55 @@ pub enum MediaLot {
     VisualNovel,
 }
 
+meta! {
+    MediaLot, Vec<MediaSource>;
+
+    AudioBook, vec![MediaSource::Audible];
+    Book, vec![
+        MediaSource::Openlibrary,
+        MediaSource::GoogleBooks,
+        MediaSource::Hardcover,
+    ];
+    Podcast, vec![
+        MediaSource::Itunes,
+        MediaSource::Listennotes,
+    ];
+    VideoGame, vec![MediaSource::Igdb];
+    Anime, vec![
+        MediaSource::Anilist,
+        MediaSource::Mal,
+    ];
+    Manga, vec![
+        MediaSource::Anilist,
+        MediaSource::MangaUpdates,
+        MediaSource::Mal,
+    ];
+    Movie, vec![MediaSource::Tmdb];
+    Music, vec![MediaSource::YoutubeMusic];
+    Show, vec![MediaSource::Tmdb];
+    VisualNovel, vec![MediaSource::Vndb];
+}
+
 /// The different sources (or providers) from which data can be obtained from.
 #[derive(
-    Debug,
-    Clone,
-    Copy,
-    PartialEq,
     Eq,
-    EnumIter,
-    DeriveActiveEnum,
-    Deserialize,
-    Serialize,
+    Copy,
     Enum,
-    Default,
     Hash,
+    Clone,
+    Debug,
+    Default,
+    EnumIter,
+    PartialEq,
+    Serialize,
     ConfigEnum,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum MediaSource {
@@ -81,13 +111,32 @@ pub enum MediaSource {
     YoutubeMusic,
 }
 
+meta! {
+    MediaSource, Option<MediaLot>;
+
+    Mal, None;
+    Vndb, None;
+    Custom, None;
+    Itunes, None;
+    Anilist, None;
+    Audible, None;
+    Listennotes, None;
+    GoogleBooks, None;
+    Openlibrary, None;
+    MangaUpdates, None;
+    Tmdb, Some(MediaLot::Movie);
+    Igdb, Some(MediaLot::VideoGame);
+    Hardcover, Some(MediaLot::Book);
+    YoutubeMusic, Some(MediaLot::Music);
+}
+
 #[derive(
     Debug, Clone, Copy, PartialEq, Eq, EnumIter, DeriveActiveEnum, Deserialize, Serialize, Enum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum UserLot {
     Admin,
@@ -99,8 +148,8 @@ pub enum UserLot {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum UserNotificationLot {
     Queued,
@@ -108,38 +157,38 @@ pub enum UserNotificationLot {
 }
 
 #[derive(
-    Debug,
-    Clone,
-    Copy,
-    PartialEq,
     Eq,
-    EnumIter,
-    DeriveActiveEnum,
-    Deserialize,
-    Serialize,
+    Ord,
+    Hash,
+    Copy,
     Enum,
+    Debug,
+    Clone,
     Display,
     Default,
+    EnumIter,
+    PartialEq,
+    Serialize,
     PartialOrd,
-    Ord,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum EntityLot {
     #[default]
     Metadata,
     Person,
-    MetadataGroup,
+    Review,
+    Workout,
     Exercise,
     Collection,
-    Workout,
+    MetadataGroup,
     WorkoutTemplate,
-    Review,
     UserMeasurement,
 }
 
@@ -159,14 +208,14 @@ pub enum EntityLot {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum SeenState {
-    Completed,
     Dropped,
-    InProgress,
     OnAHold,
+    Completed,
+    InProgress,
 }
 
 #[derive(
@@ -185,8 +234,8 @@ pub enum SeenState {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum Visibility {
     #[default]
@@ -209,8 +258,8 @@ pub enum Visibility {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum ImportSource {
     Igdb,
@@ -232,70 +281,70 @@ pub enum ImportSource {
 }
 
 #[derive(
+    Eq,
+    Copy,
+    Enum,
+    Hash,
     Debug,
     Clone,
-    Serialize,
-    Enum,
-    Copy,
-    Deserialize,
-    DeriveActiveEnum,
+    Default,
     EnumIter,
-    Eq,
     PartialEq,
-    Default,
+    Serialize,
     ConfigEnum,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseMuscle {
-    #[default]
-    Abdominals,
-    Abductors,
-    Adductors,
+    Lats,
+    Neck,
+    Traps,
+    Chest,
     Biceps,
     Calves,
-    Chest,
-    Forearms,
     Glutes,
-    Hamstrings,
-    Lats,
+    Triceps,
+    Forearms,
+    Abductors,
+    Adductors,
     #[strum(serialize = "lower_back")]
     #[serde(alias = "lower back")]
     LowerBack,
+    Shoulders,
+    #[default]
+    Abdominals,
+    Hamstrings,
     #[strum(serialize = "middle_back")]
     #[serde(alias = "middle back")]
     MiddleBack,
-    Neck,
     Quadriceps,
-    Shoulders,
-    Traps,
-    Triceps,
 }
 
 #[derive(
-    Debug,
-    Clone,
-    Serialize,
-    Enum,
+    Eq,
     Copy,
-    Deserialize,
-    DeriveActiveEnum,
+    Enum,
+    Hash,
+    Clone,
+    Debug,
+    Default,
     EnumIter,
-    Eq,
     PartialEq,
-    Default,
+    Serialize,
     ConfigEnum,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseForce {
@@ -306,24 +355,24 @@ pub enum ExerciseForce {
 }
 
 #[derive(
-    Debug,
-    Clone,
-    Serialize,
+    Eq,
     Enum,
     Copy,
-    Deserialize,
-    DeriveActiveEnum,
+    Hash,
+    Clone,
+    Debug,
+    Default,
     EnumIter,
-    Eq,
     PartialEq,
-    Default,
+    Serialize,
     ConfigEnum,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseLevel {
@@ -348,8 +397,8 @@ pub enum ExerciseLevel {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseMechanic {
@@ -358,75 +407,105 @@ pub enum ExerciseMechanic {
 }
 
 #[derive(
-    Debug,
-    Clone,
-    Serialize,
+    Eq,
+    Hash,
     Enum,
     Copy,
-    Deserialize,
-    DeriveActiveEnum,
+    Debug,
+    Clone,
+    Default,
     EnumIter,
-    Eq,
     PartialEq,
-    Default,
+    Serialize,
     ConfigEnum,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseEquipment {
     Bands,
+    Cable,
+    Other,
     #[default]
     Barbell,
+    Machine,
     BodyOnly,
-    Cable,
     Dumbbell,
-    #[serde(alias = "exercise ball")]
-    ExerciseBall,
-    #[serde(alias = "e-z curl bar")]
-    EZCurlBar,
     #[serde(alias = "foam roll")]
     FoamRoll,
+    #[serde(alias = "e-z curl bar")]
+    EZCurlBar,
     #[serde(alias = "body only")]
     Kettlebells,
-    Machine,
+    #[serde(alias = "exercise ball")]
+    ExerciseBall,
     #[serde(alias = "medicine ball")]
     MedicineBall,
-    Other,
 }
 
 /// The different types of exercises that can be done.
 #[derive(
-    Clone,
-    Debug,
-    Deserialize,
-    Serialize,
-    DeriveActiveEnum,
     Eq,
-    PartialEq,
     Enum,
     Copy,
+    Hash,
+    Clone,
+    Debug,
+    Default,
     EnumIter,
+    PartialEq,
+    Serialize,
     ConfigEnum,
-    Default,
-    Hash,
+    Deserialize,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum ExerciseLot {
-    Duration,
-    DistanceAndDuration,
     Reps,
+    Duration,
     #[default]
     RepsAndWeight,
+    RepsAndDuration,
+    DistanceAndDuration,
+    RepsAndDurationAndDistance,
+}
+
+meta! {
+    ExerciseLot, Vec<WorkoutSetPersonalBest>;
+
+    Reps, vec![WorkoutSetPersonalBest::Reps];
+    Duration, vec![WorkoutSetPersonalBest::Time];
+    RepsAndDuration, vec![
+        WorkoutSetPersonalBest::Reps,
+        WorkoutSetPersonalBest::Time
+    ];
+    DistanceAndDuration, vec![
+        WorkoutSetPersonalBest::Pace,
+        WorkoutSetPersonalBest::Time,
+        WorkoutSetPersonalBest::Distance,
+    ];
+    RepsAndDurationAndDistance, vec![
+        WorkoutSetPersonalBest::Reps,
+        WorkoutSetPersonalBest::Pace,
+        WorkoutSetPersonalBest::Time,
+        WorkoutSetPersonalBest::Distance,
+    ];
+    RepsAndWeight, vec![
+        WorkoutSetPersonalBest::Reps,
+        WorkoutSetPersonalBest::OneRm,
+        WorkoutSetPersonalBest::Weight,
+        WorkoutSetPersonalBest::Volume,
+    ];
 }
 
 #[derive(
@@ -445,8 +524,8 @@ pub enum ExerciseLot {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum ExerciseSource {
     Github,
@@ -470,76 +549,77 @@ pub enum ExerciseSource {
 )]
 #[serde(rename_all = "snake_case")]
 pub enum WorkoutSetPersonalBest {
-    #[default]
-    Weight,
-    OneRm,
-    Volume,
     Time,
     Pace,
     Reps,
+    OneRm,
+    Volume,
+    #[default]
+    Weight,
+    Distance,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumIter, DeriveActiveEnum, Deserialize, Serialize)]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 pub enum MetadataToMetadataRelation {
     Suggestion,
 }
 
 #[derive(
+    Eq,
+    Enum,
     Copy,
+    Hash,
     Clone,
     Debug,
-    Enum,
-    PartialEq,
-    Eq,
-    DeriveActiveEnum,
+    Display,
     EnumIter,
     Serialize,
+    PartialEq,
     Deserialize,
-    Hash,
-    Display,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[strum(serialize_all = "snake_case")]
 pub enum UserToMediaReason {
     // There is at-least one element in the seen history
     Seen,
+    Owned,
     // User has watched this media completely (mostly applies to shows, podcasts etc.)
     Finished,
     Reviewed,
-    Collection,
     Reminder,
-    Owned,
-    Monitoring,
     Watchlist,
+    Collection,
+    Monitoring,
 }
 
 #[derive(
+    Eq,
+    Enum,
     Copy,
+    Hash,
     Clone,
     Debug,
-    Enum,
-    PartialEq,
-    Eq,
-    DeriveActiveEnum,
+    Display,
     EnumIter,
     Serialize,
+    PartialEq,
     Deserialize,
-    Hash,
-    Display,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum IntegrationLot {
@@ -549,23 +629,23 @@ pub enum IntegrationLot {
 }
 
 #[derive(
+    Eq,
     Copy,
+    Hash,
+    Enum,
     Clone,
     Debug,
-    Enum,
-    PartialEq,
-    Eq,
-    DeriveActiveEnum,
+    Display,
     EnumIter,
     Serialize,
+    PartialEq,
     Deserialize,
-    Hash,
-    Display,
+    DeriveActiveEnum,
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum IntegrationProvider {
@@ -598,18 +678,18 @@ pub enum IntegrationProvider {
 )]
 #[sea_orm(
     rs_type = "String",
-    db_type = "String(StringLen::None)",
-    rename_all = "snake_case"
+    rename_all = "snake_case",
+    db_type = "String(StringLen::None)"
 )]
 #[serde(rename_all = "snake_case")]
 pub enum NotificationPlatformLot {
+    Ntfy,
+    Email,
+    Gotify,
     Apprise,
     Discord,
-    Gotify,
-    Ntfy,
-    PushBullet,
     PushOver,
-    PushSafer,
-    Email,
     Telegram,
+    PushSafer,
+    PushBullet,
 }
diff --git a/crates/services/supporting/Cargo.toml b/crates/services/supporting/Cargo.toml
index 0d4195a2d3..beb1e5d558 100644
--- a/crates/services/supporting/Cargo.toml
+++ b/crates/services/supporting/Cargo.toml
@@ -15,6 +15,7 @@ common-utils = { path = "../../utils/common" }
 config = { path = "../../config" }
 dependent-models = { path = "../../models/dependent" }
 enum-models = { path = "../../models/enum" }
+enum_meta = { workspace = true }
 env-utils = { path = "../../utils/env" }
 file-storage-service = { path = "../../services/file-storage" }
 isolang = { workspace = true }
diff --git a/crates/services/supporting/src/lib.rs b/crates/services/supporting/src/lib.rs
index a051f497ba..c9ecb39426 100644
--- a/crates/services/supporting/src/lib.rs
+++ b/crates/services/supporting/src/lib.rs
@@ -7,17 +7,17 @@ use cache_service::CacheService;
 use chrono::{NaiveDate, TimeZone, Utc};
 use common_models::BackendError;
 use common_utils::{
-    convert_naive_to_utc, ryot_log, COMPILATION_TIMESTAMP, EXERCISE_LOT_MAPPINGS,
-    METADATA_GROUP_SOURCE_LOT_MAPPINGS, METADATA_LOT_MAPPINGS, PAGE_SIZE, PEOPLE_SEARCH_SOURCES,
+    convert_naive_to_utc, ryot_log, COMPILATION_TIMESTAMP, PAGE_SIZE, PEOPLE_SEARCH_SOURCES,
 };
 use dependent_models::{
     ApplicationCacheKey, ApplicationCacheValue, CoreDetails, ExerciseFilters, ExerciseParameters,
     ExerciseParametersLotMapping, MetadataGroupSourceLotMapping, MetadataLotSourceMappings,
     ProviderLanguageInformation,
 };
+use enum_meta::Meta;
 use enum_models::{
     ExerciseEquipment, ExerciseForce, ExerciseLevel, ExerciseLot, ExerciseMechanic, ExerciseMuscle,
-    MediaSource,
+    MediaLot, MediaSource,
 };
 use env_utils::{APP_VERSION, UNKEY_API_ID};
 use file_storage_service::FileStorageService;
@@ -150,18 +150,17 @@ impl SupportingService {
             token_valid_for_days: self.config.users.token_valid_for_days,
             repository_link: "https://github.com/ignisda/ryot".to_owned(),
             is_server_key_validated: self.get_is_server_key_validated().await,
-            metadata_group_source_lot_mappings: METADATA_GROUP_SOURCE_LOT_MAPPINGS
-                .iter()
-                .map(|(source, lot)| MetadataGroupSourceLotMapping {
-                    lot: *lot,
-                    source: *source,
+            metadata_lot_source_mappings: MediaLot::iter()
+                .map(|lot| MetadataLotSourceMappings {
+                    lot,
+                    sources: lot.meta(),
                 })
                 .collect(),
-            metadata_lot_source_mappings: METADATA_LOT_MAPPINGS
-                .iter()
-                .map(|(lot, sources)| MetadataLotSourceMappings {
-                    lot: *lot,
-                    sources: sources.to_vec(),
+            metadata_group_source_lot_mappings: MediaSource::iter()
+                .flat_map(|source| {
+                    source
+                        .meta()
+                        .map(|lot| MetadataGroupSourceLotMapping { source, lot })
                 })
                 .collect(),
             exercise_parameters: ExerciseParameters {
@@ -169,15 +168,14 @@ impl SupportingService {
                     lot: ExerciseLot::iter().collect_vec(),
                     level: ExerciseLevel::iter().collect_vec(),
                     force: ExerciseForce::iter().collect_vec(),
+                    muscle: ExerciseMuscle::iter().collect_vec(),
                     mechanic: ExerciseMechanic::iter().collect_vec(),
                     equipment: ExerciseEquipment::iter().collect_vec(),
-                    muscle: ExerciseMuscle::iter().collect_vec(),
                 },
-                lot_mapping: EXERCISE_LOT_MAPPINGS
-                    .iter()
-                    .map(|(lot, pbs)| ExerciseParametersLotMapping {
-                        lot: *lot,
-                        bests: pbs.to_vec(),
+                lot_mapping: ExerciseLot::iter()
+                    .map(|lot| ExerciseParametersLotMapping {
+                        lot,
+                        bests: lot.meta(),
                     })
                     .collect(),
             },
diff --git a/crates/utils/common/src/lib.rs b/crates/utils/common/src/lib.rs
index cc2a6e2719..796380eef3 100644
--- a/crates/utils/common/src/lib.rs
+++ b/crates/utils/common/src/lib.rs
@@ -1,7 +1,7 @@
 use std::{convert::TryInto, fmt};
 
 use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
-use enum_models::{ExerciseLot, MediaLot, MediaSource, WorkoutSetPersonalBest};
+use enum_models::MediaSource;
 use env_utils::APP_VERSION;
 use reqwest::header::HeaderValue;
 use serde::de;
@@ -34,52 +34,6 @@ pub const SHOW_SPECIAL_SEASON_NAMES: [&str; 2] = ["Specials", "Extras"];
 pub static APPLICATION_JSON_HEADER: HeaderValue = HeaderValue::from_static("application/json");
 pub const FRONTEND_OAUTH_ENDPOINT: &str = "/api/auth";
 pub const PAGE_SIZE: i32 = 20;
-pub const EXERCISE_LOT_MAPPINGS: &[(ExerciseLot, &[WorkoutSetPersonalBest])] = &[
-    (ExerciseLot::Duration, &[WorkoutSetPersonalBest::Time]),
-    (
-        ExerciseLot::DistanceAndDuration,
-        &[WorkoutSetPersonalBest::Pace, WorkoutSetPersonalBest::Time],
-    ),
-    (
-        ExerciseLot::RepsAndWeight,
-        &[
-            WorkoutSetPersonalBest::Weight,
-            WorkoutSetPersonalBest::OneRm,
-            WorkoutSetPersonalBest::Volume,
-            WorkoutSetPersonalBest::Reps,
-        ],
-    ),
-    (ExerciseLot::Reps, &[WorkoutSetPersonalBest::Reps]),
-];
-pub const METADATA_LOT_MAPPINGS: &[(MediaLot, &[MediaSource])] = &[
-    (MediaLot::AudioBook, &[MediaSource::Audible]),
-    (
-        MediaLot::Book,
-        &[
-            MediaSource::Openlibrary,
-            MediaSource::GoogleBooks,
-            MediaSource::Hardcover,
-        ],
-    ),
-    (
-        MediaLot::Podcast,
-        &[MediaSource::Itunes, MediaSource::Listennotes],
-    ),
-    (MediaLot::VideoGame, &[MediaSource::Igdb]),
-    (MediaLot::Anime, &[MediaSource::Anilist, MediaSource::Mal]),
-    (
-        MediaLot::Manga,
-        &[
-            MediaSource::Anilist,
-            MediaSource::MangaUpdates,
-            MediaSource::Mal,
-        ],
-    ),
-    (MediaLot::Movie, &[MediaSource::Tmdb]),
-    (MediaLot::Music, &[MediaSource::YoutubeMusic]),
-    (MediaLot::Show, &[MediaSource::Tmdb]),
-    (MediaLot::VisualNovel, &[MediaSource::Vndb]),
-];
 
 pub const PEOPLE_SEARCH_SOURCES: [MediaSource; 9] = [
     MediaSource::Tmdb,
@@ -93,13 +47,6 @@ pub const PEOPLE_SEARCH_SOURCES: [MediaSource; 9] = [
     MediaSource::Hardcover,
 ];
 
-pub const METADATA_GROUP_SOURCE_LOT_MAPPINGS: &[(MediaSource, MediaLot)] = &[
-    (MediaSource::Tmdb, MediaLot::Movie),
-    (MediaSource::Igdb, MediaLot::VideoGame),
-    (MediaSource::Hardcover, MediaLot::Book),
-    (MediaSource::YoutubeMusic, MediaLot::Music),
-];
-
 pub fn get_first_and_last_day_of_month(year: i32, month: u32) -> (NaiveDate, NaiveDate) {
     let first_day = NaiveDate::from_ymd_opt(year, month, 1).unwrap();
     let last_day = NaiveDate::from_ymd_opt(year, month + 1, 1)
diff --git a/crates/utils/dependent/Cargo.toml b/crates/utils/dependent/Cargo.toml
index da8ed4da50..81d87ce107 100644
--- a/crates/utils/dependent/Cargo.toml
+++ b/crates/utils/dependent/Cargo.toml
@@ -16,6 +16,7 @@ database-utils = { path = "../database" }
 dependent-models = { path = "../../models/dependent" }
 either = { workspace = true }
 enum-models = { path = "../../models/enum" }
+enum_meta = { workspace = true }
 file-storage-service = { path = "../../services/file-storage" }
 fitness-models = { path = "../../models/fitness" }
 importer-models = { path = "../../models/importer" }
diff --git a/crates/utils/dependent/src/lib.rs b/crates/utils/dependent/src/lib.rs
index 04be11d93c..cd04213244 100644
--- a/crates/utils/dependent/src/lib.rs
+++ b/crates/utils/dependent/src/lib.rs
@@ -10,8 +10,8 @@ use common_models::{
     StringIdObject, UserLevelCacheKey, UserNotificationContent,
 };
 use common_utils::{
-    acquire_lock, ryot_log, sleep_for_n_seconds, EXERCISE_LOT_MAPPINGS,
-    MAX_IMPORT_RETRIES_FOR_PARTIAL_STATE, PAGE_SIZE, SHOW_SPECIAL_SEASON_NAMES,
+    acquire_lock, ryot_log, sleep_for_n_seconds, MAX_IMPORT_RETRIES_FOR_PARTIAL_STATE, PAGE_SIZE,
+    SHOW_SPECIAL_SEASON_NAMES,
 };
 use database_models::{
     collection, collection_to_entity, exercise,
@@ -38,6 +38,7 @@ use dependent_models::{
     UserWorkoutsTemplatesListResponse,
 };
 use either::Either;
+use enum_meta::Meta;
 use enum_models::{
     EntityLot, ExerciseLot, ExerciseSource, MediaLot, MediaSource, MetadataToMetadataRelation,
     SeenState, UserNotificationLot, UserToMediaReason, Visibility, WorkoutSetPersonalBest,
@@ -1640,22 +1641,30 @@ fn get_personal_best(
     pb_type: &WorkoutSetPersonalBest,
 ) -> Option<Decimal> {
     match pb_type {
-        WorkoutSetPersonalBest::Weight => value.statistic.weight,
-        WorkoutSetPersonalBest::Time => value.statistic.duration,
         WorkoutSetPersonalBest::Reps => value.statistic.reps,
+        WorkoutSetPersonalBest::Pace => calculate_pace(value),
         WorkoutSetPersonalBest::OneRm => calculate_one_rm(value),
+        WorkoutSetPersonalBest::Time => value.statistic.duration,
+        WorkoutSetPersonalBest::Weight => value.statistic.weight,
         WorkoutSetPersonalBest::Volume => calculate_volume(value),
-        WorkoutSetPersonalBest::Pace => calculate_pace(value),
+        WorkoutSetPersonalBest::Distance => value.statistic.distance,
     }
 }
 
 /// Set the invalid statistics to `None` according to the type of exercise.
 fn clean_values(value: &mut UserWorkoutSetRecord, exercise_lot: &ExerciseLot) {
-    let mut stats = WorkoutSetStatistic {
-        ..Default::default()
-    };
+    let mut stats = WorkoutSetStatistic::default();
     match exercise_lot {
-        ExerciseLot::Duration => stats.duration = value.statistic.duration,
+        ExerciseLot::Reps => {
+            stats.reps = value.statistic.reps;
+        }
+        ExerciseLot::Duration => {
+            stats.duration = value.statistic.duration;
+        }
+        ExerciseLot::RepsAndDuration => {
+            stats.reps = value.statistic.reps;
+            stats.duration = value.statistic.duration;
+        }
         ExerciseLot::DistanceAndDuration => {
             stats.distance = value.statistic.distance;
             stats.duration = value.statistic.duration;
@@ -1664,8 +1673,10 @@ fn clean_values(value: &mut UserWorkoutSetRecord, exercise_lot: &ExerciseLot) {
             stats.reps = value.statistic.reps;
             stats.weight = value.statistic.weight;
         }
-        ExerciseLot::Reps => {
+        ExerciseLot::RepsAndDurationAndDistance => {
             stats.reps = value.statistic.reps;
+            stats.duration = value.statistic.duration;
+            stats.distance = value.statistic.distance;
         }
     }
     value.statistic = stats;
@@ -1906,11 +1917,7 @@ pub async fn create_or_update_user_workout(
             .clone()
             .unwrap_or_default()
             .personal_bests;
-        let types_of_prs = EXERCISE_LOT_MAPPINGS
-            .iter()
-            .find(|lm| lm.0 == db_ex.lot)
-            .map(|lm| lm.1)
-            .unwrap();
+        let types_of_prs = db_ex.lot.meta();
         for best_type in types_of_prs.iter() {
             let set_idx = get_index_of_highest_pb(&sets, best_type).unwrap();
             let possible_record = personal_bests
diff --git a/docs/includes/export-schema.ts b/docs/includes/export-schema.ts
index a265818ccd..8b63681d04 100644
--- a/docs/includes/export-schema.ts
+++ b/docs/includes/export-schema.ts
@@ -233,13 +233,13 @@ export interface WorkoutDuration {
 }
 
 /** The different types of exercises that can be done. */
-export type ExerciseLot = 'duration' | 'distance_and_duration' | 'reps' | 'reps_and_weight';
+export type ExerciseLot = 'reps' | 'duration' | 'reps_and_weight' | 'reps_and_duration' | 'distance_and_duration' | 'reps_and_duration_and_distance';
 
 /** The types of set (mostly characterized by exertion level). */
 export type SetLot = 'normal' | 'warm_up' | 'drop' | 'failure';
 
 /** The different types of personal bests that can be achieved on a set. */
-export type WorkoutSetPersonalBest = 'weight' | 'one_rm' | 'volume' | 'time' | 'pace' | 'reps';
+export type WorkoutSetPersonalBest = 'time' | 'pace' | 'reps' | 'one_rm' | 'volume' | 'weight' | 'distance';
 
 /** Details about the statistics of the set performed. */
 export interface WorkoutSetStatistic {
@@ -291,7 +291,7 @@ export interface ProcessedExercise {
 	id: string;
 	/**
 	 * @default 'reps_and_weight'
-	 * @type {'duration' | 'distance_and_duration' | 'reps' | 'reps_and_weight'}
+	 * @type {'reps' | 'duration' | 'reps_and_weight' | 'reps_and_duration' | 'distance_and_duration' | 'reps_and_duration_and_distance'}
 	 */
 	lot: ExerciseLot;
 	notes: string[];
@@ -324,12 +324,12 @@ export interface WorkoutSummaryExercise {
 	num_sets: number;
 }
 
-export type ExerciseEquipment = 'bands' | 'barbell' | 'body_only' | 'cable' | 'dumbbell' | 'exercise_ball' | 'ez_curl_bar' | 'foam_roll' | 'kettlebells' | 'machine' | 'medicine_ball' | 'other';
+export type ExerciseEquipment = 'bands' | 'cable' | 'other' | 'barbell' | 'machine' | 'body_only' | 'dumbbell' | 'foam_roll' | 'ez_curl_bar' | 'kettlebells' | 'exercise_ball' | 'medicine_ball';
 
 export interface WorkoutEquipmentFocusedSummary {
 	/**
 	 * @default 'barbell'
-	 * @type {'bands' | 'barbell' | 'body_only' | 'cable' | 'dumbbell' | 'exercise_ball' | 'ez_curl_bar' | 'foam_roll' | 'kettlebells' | 'machine' | 'medicine_ball' | 'other'}
+	 * @type {'bands' | 'cable' | 'other' | 'barbell' | 'machine' | 'body_only' | 'dumbbell' | 'foam_roll' | 'ez_curl_bar' | 'kettlebells' | 'exercise_ball' | 'medicine_ball'}
 	 */
 	equipment: ExerciseEquipment;
 	exercises: number[];
@@ -361,18 +361,18 @@ export interface WorkoutLotFocusedSummary {
 	exercises: number[];
 	/**
 	 * @default 'reps_and_weight'
-	 * @type {'duration' | 'distance_and_duration' | 'reps' | 'reps_and_weight'}
+	 * @type {'reps' | 'duration' | 'reps_and_weight' | 'reps_and_duration' | 'distance_and_duration' | 'reps_and_duration_and_distance'}
 	 */
 	lot: ExerciseLot;
 }
 
-export type ExerciseMuscle = 'abdominals' | 'abductors' | 'adductors' | 'biceps' | 'calves' | 'chest' | 'forearms' | 'glutes' | 'hamstrings' | 'lats' | 'lower_back' | 'middle_back' | 'neck' | 'quadriceps' | 'shoulders' | 'traps' | 'triceps';
+export type ExerciseMuscle = 'lats' | 'neck' | 'traps' | 'chest' | 'biceps' | 'calves' | 'glutes' | 'triceps' | 'forearms' | 'abductors' | 'adductors' | 'lower_back' | 'shoulders' | 'abdominals' | 'hamstrings' | 'middle_back' | 'quadriceps';
 
 export interface WorkoutMuscleFocusedSummary {
 	exercises: number[];
 	/**
 	 * @default 'abdominals'
-	 * @type {'abdominals' | 'abductors' | 'adductors' | 'biceps' | 'calves' | 'chest' | 'forearms' | 'glutes' | 'hamstrings' | 'lats' | 'lower_back' | 'middle_back' | 'neck' | 'quadriceps' | 'shoulders' | 'traps' | 'triceps'}
+	 * @type {'lats' | 'neck' | 'traps' | 'chest' | 'biceps' | 'calves' | 'glutes' | 'triceps' | 'forearms' | 'abductors' | 'adductors' | 'lower_back' | 'shoulders' | 'abdominals' | 'hamstrings' | 'middle_back' | 'quadriceps'}
 	 */
 	muscle: ExerciseMuscle;
 }
diff --git a/libs/generated/src/graphql/backend/gql.ts b/libs/generated/src/graphql/backend/gql.ts
index 2175f6fb7b..8e8b86c764 100644
--- a/libs/generated/src/graphql/backend/gql.ts
+++ b/libs/generated/src/graphql/backend/gql.ts
@@ -13,7 +13,19 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
  * Therefore it is highly recommended to use the babel or swc plugin for production.
  * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
  */
-const documents = {
+type Documents = {
+    "mutation RegisterUser($input: RegisterUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation UpdateCustomMetadata($input: UpdateCustomMetadataInput!) {\n  updateCustomMetadata(input: $input)\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateUserWorkout($input: UserWorkoutInput!) {\n  createOrUpdateUserWorkout(input: $input)\n}\n\nmutation CreateOrUpdateUserWorkoutTemplate($input: UserWorkoutInput!) {\n  createOrUpdateUserWorkoutTemplate(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeleteUserWorkoutTemplate($workoutTemplateId: String!) {\n  deleteUserWorkoutTemplate(workoutTemplateId: $workoutTemplateId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob {\n  deployExportJob\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation DeployUpdateMetadataGroupJob($metadataGroupId: String!) {\n  deployUpdateMetadataGroupJob(metadataGroupId: $metadataGroupId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkoutAttributes($input: UpdateUserWorkoutAttributesInput!) {\n  updateUserWorkoutAttributes(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation DisassociateMetadata($metadataId: String!) {\n  disassociateMetadata(metadataId: $metadataId)\n}\n\nmutation CreateOrUpdateReview($input: CreateOrUpdateReviewInput!) {\n  createOrUpdateReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UserPreferencesInput!) {\n  updateUserPreference(input: $input)\n}\n\nmutation CreateAccessLink($input: CreateAccessLinkInput!) {\n  createAccessLink(input: $input) {\n    id\n  }\n}\n\nmutation ProcessAccessLink($input: ProcessAccessLinkInput!) {\n  processAccessLink(input: $input) {\n    __typename\n    ... on ProcessAccessLinkError {\n      error\n    }\n    ... on ProcessAccessLinkResponse {\n      apiKey\n      redirectTo\n      tokenValidForDays\n    }\n  }\n}\n\nmutation RevokeAccessLink($accessLinkId: String!) {\n  revokeAccessLink(accessLinkId: $accessLinkId)\n}\n\nmutation UpdateUserExerciseSettings($input: UpdateUserExerciseSettings!) {\n  updateUserExerciseSettings(input: $input)\n}\n\nmutation MergeExercise($mergeFrom: String!, $mergeInto: String!) {\n  mergeExercise(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation MarkEntityAsPartial($input: MarkEntityAsPartialInput!) {\n  markEntityAsPartial(input: $input)\n}\n\nmutation MarkNotificationsAsAddressed($notificationIds: [String!]!) {\n  markNotificationsAsAddressed(notificationIds: $notificationIds)\n}\n\nmutation ExpireCacheKey($cacheId: UUID!) {\n  expireCacheKey(cacheId: $cacheId)\n}": typeof types.RegisterUserDocument,
+    "query MetadataDetails($metadataId: String!) {\n  metadataDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    source\n    isNsfw\n    isPartial\n    sourceUrl\n    identifier\n    description\n    suggestions\n    publishYear\n    publishDate\n    providerRating\n    createdByUserId\n    productionStatus\n    originalLanguage\n    animeSpecifics {\n      episodes\n    }\n    audioBookSpecifics {\n      runtime\n    }\n    movieSpecifics {\n      runtime\n    }\n    genres {\n      id\n      name\n    }\n    group {\n      id\n      name\n      part\n    }\n    watchProviders {\n      name\n      image\n      languages\n    }\n    bookSpecifics {\n      pages\n      isCompilation\n    }\n    mangaSpecifics {\n      volumes\n      chapters\n    }\n    assets {\n      images\n      videos {\n        videoId\n        source\n      }\n    }\n    creators {\n      name\n      items {\n        id\n        name\n        image\n        character\n      }\n    }\n    podcastSpecifics {\n      episodes {\n        id\n        title\n        overview\n        thumbnail\n        number\n        runtime\n        publishDate\n      }\n      totalEpisodes\n    }\n    showSpecifics {\n      totalSeasons\n      totalEpisodes\n      runtime\n      seasons {\n        id\n        seasonNumber\n        name\n        overview\n        backdropImages\n        posterImages\n        episodes {\n          id\n          name\n          posterImages\n          episodeNumber\n          publishDate\n          name\n          overview\n          runtime\n        }\n      }\n    }\n    visualNovelSpecifics {\n      length\n    }\n    videoGameSpecifics {\n      platforms\n    }\n    musicSpecifics {\n      duration\n      viewCount\n      byVariousArtists\n    }\n  }\n}": typeof types.MetadataDetailsDocument,
+    "query PersonDetails($personId: String!) {\n  personDetails(personId: $personId) {\n    associatedMetadata {\n      ...PersonDetailsGroupedByRolePart\n    }\n    associatedMetadataGroups {\n      ...PersonDetailsGroupedByRolePart\n    }\n    details {\n      id\n      name\n      place\n      source\n      gender\n      website\n      deathDate\n      birthDate\n      isPartial\n      sourceUrl\n      identifier\n      description\n      displayImages\n      alternateNames\n    }\n  }\n}": typeof types.PersonDetailsDocument,
+    "query UserAnalytics($input: UserAnalyticsInput!) {\n  userAnalytics(input: $input) {\n    hours {\n      hour\n      entities {\n        entityId\n        entityLot\n        metadataLot\n      }\n    }\n    activities {\n      groupedBy\n      totalCount\n      totalDuration\n      items {\n        day\n        bookCount\n        showCount\n        totalCount\n        movieCount\n        musicCount\n        animeCount\n        mangaCount\n        workoutCount\n        podcastCount\n        totalDuration\n        totalBookPages\n        audioBookCount\n        videoGameCount\n        totalReviewCount\n        visualNovelCount\n        totalWorkoutReps\n        totalShowDuration\n        totalMovieDuration\n        totalMusicDuration\n        totalMetadataCount\n        totalWorkoutWeight\n        totalPodcastDuration\n        totalWorkoutDistance\n        totalWorkoutRestTime\n        totalWorkoutDuration\n        userMeasurementCount\n        totalVideoGameDuration\n        totalAudioBookDuration\n        totalPersonReviewCount\n        totalVisualNovelDuration\n        totalMetadataReviewCount\n        totalWorkoutPersonalBests\n        totalCollectionReviewCount\n        totalMetadataGroupReviewCount\n      }\n    }\n    fitness {\n      workoutReps\n      workoutCount\n      workoutWeight\n      workoutDistance\n      workoutDuration\n      workoutRestTime\n      measurementCount\n      workoutPersonalBests\n      workoutCaloriesBurnt\n      workoutExercises {\n        count\n        exercise\n      }\n      workoutMuscles {\n        count\n        muscle\n      }\n      workoutEquipments {\n        count\n        equipment\n      }\n    }\n  }\n}": typeof types.UserAnalyticsDocument,
+    "query UserDetails {\n  userDetails {\n    __typename\n    ... on User {\n      id\n      lot\n      name\n      isDisabled\n      oidcIssuerId\n      preferences {\n        general {\n          reviewScale\n          gridPacking\n          displayNsfw\n          disableVideos\n          persistQueries\n          disableReviews\n          disableIntegrations\n          disableWatchProviders\n          showSpoilersInCalendar\n          disableNavigationAnimation\n          dashboard {\n            hidden\n            section\n            numElements\n            deduplicateMedia\n          }\n          watchProviders {\n            lot\n            values\n          }\n        }\n        fitness {\n          exercises {\n            unitSystem\n            setRestTimers {\n              ...SetRestTimersPart\n            }\n          }\n          logging {\n            muteSounds\n            caloriesBurntUnit\n            promptForRestTimer\n            showDetailsWhileEditing\n          }\n          measurements {\n            custom {\n              name\n              dataType\n            }\n            inbuilt {\n              weight\n              bodyMassIndex\n              totalBodyWater\n              muscle\n              leanBodyMass\n              bodyFat\n              boneMass\n              visceralFat\n              waistCircumference\n              waistToHeightRatio\n              hipCircumference\n              waistToHipRatio\n              chestCircumference\n              thighCircumference\n              bicepsCircumference\n              neckCircumference\n              bodyFatCaliper\n              chestSkinfold\n              abdominalSkinfold\n              thighSkinfold\n              basalMetabolicRate\n              totalDailyEnergyExpenditure\n              calories\n            }\n          }\n        }\n        notifications {\n          toSend\n          enabled\n        }\n        featuresEnabled {\n          analytics {\n            enabled\n          }\n          others {\n            calendar\n            collections\n          }\n          fitness {\n            enabled\n            workouts\n            templates\n            measurements\n          }\n          media {\n            enabled\n            groups\n            people\n            genres\n            specific\n          }\n        }\n      }\n    }\n  }\n}": typeof types.UserDetailsDocument,
+    "query UserExerciseDetails($exerciseId: String!) {\n  userExerciseDetails(exerciseId: $exerciseId) {\n    collections {\n      ...CollectionPart\n    }\n    reviews {\n      ...ReviewItemPart\n    }\n    history {\n      idx\n      workoutId\n      workoutEndOn\n      bestSet {\n        ...WorkoutSetRecordPart\n      }\n    }\n    details {\n      exerciseId\n      createdOn\n      lastUpdatedOn\n      exerciseNumTimesInteracted\n      exerciseExtraInformation {\n        settings {\n          excludeFromAnalytics\n          setRestTimers {\n            ...SetRestTimersPart\n          }\n        }\n        lifetimeStats {\n          weight\n          reps\n          distance\n          duration\n          personalBestsAchieved\n        }\n        personalBests {\n          lot\n          sets {\n            setIdx\n            workoutId\n            exerciseIdx\n          }\n        }\n      }\n    }\n  }\n}": typeof types.UserExerciseDetailsDocument,
+    "query UserMeasurementsList($input: UserMeasurementsListInput!) {\n  userMeasurementsList(input: $input) {\n    timestamp\n    name\n    comment\n    stats {\n      weight\n      bodyMassIndex\n      totalBodyWater\n      muscle\n      leanBodyMass\n      bodyFat\n      boneMass\n      visceralFat\n      waistCircumference\n      waistToHeightRatio\n      hipCircumference\n      waistToHipRatio\n      chestCircumference\n      thighCircumference\n      bicepsCircumference\n      neckCircumference\n      bodyFatCaliper\n      chestSkinfold\n      abdominalSkinfold\n      thighSkinfold\n      basalMetabolicRate\n      totalDailyEnergyExpenditure\n      calories\n      custom\n    }\n  }\n}": typeof types.UserMeasurementsListDocument,
+    "query UserMetadataDetails($metadataId: String!) {\n  userMetadataDetails(metadataId: $metadataId) {\n    mediaReason\n    hasInteracted\n    averageRating\n    seenByAllCount\n    seenByUserCount\n    recentlyConsumed\n    reviews {\n      ...ReviewItemPart\n    }\n    history {\n      ...SeenPart\n    }\n    nextEntry {\n      season\n      volume\n      episode\n      chapter\n    }\n    inProgress {\n      ...SeenPart\n    }\n    collections {\n      ...CollectionPart\n    }\n    showProgress {\n      timesSeen\n      seasonNumber\n      episodes {\n        episodeNumber\n        timesSeen\n      }\n    }\n    podcastProgress {\n      episodeNumber\n      timesSeen\n    }\n  }\n}": typeof types.UserMetadataDetailsDocument,
+    "query GetOidcRedirectUrl {\n  getOidcRedirectUrl\n}\n\nquery UserByOidcIssuerId($oidcIssuerId: String!) {\n  userByOidcIssuerId(oidcIssuerId: $oidcIssuerId)\n}\n\nquery GetOidcToken($code: String!) {\n  getOidcToken(code: $code) {\n    subject\n    email\n  }\n}\n\nquery GetPresignedS3Url($key: String!) {\n  getPresignedS3Url(key: $key)\n}\n\nquery UserExports {\n  userExports {\n    url\n    key\n    size\n    endedAt\n    startedAt\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\n    cacheId\n    response {\n      id\n      name\n      count\n      isDefault\n      description\n      creator {\n        id\n        name\n      }\n      collaborators {\n        id\n        name\n      }\n      informationTemplate {\n        lot\n        name\n        required\n        description\n        defaultValue\n      }\n    }\n  }\n}\n\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    name\n    provider\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\n    syncToOwnedCollection\n  }\n}\n\nquery UserNotificationPlatforms {\n  userNotificationPlatforms {\n    id\n    lot\n    createdOn\n    isDisabled\n    description\n  }\n}\n\nquery UsersList($query: String) {\n  usersList(query: $query) {\n    id\n    lot\n    name\n    isDisabled\n  }\n}\n\nquery UserMetadataRecommendations {\n  userMetadataRecommendations {\n    cacheId\n    response\n  }\n}\n\nquery UserUpcomingCalendarEvents($input: UserUpcomingCalendarEventInput!) {\n  userUpcomingCalendarEvents(input: $input) {\n    ...CalendarEventPart\n  }\n}\n\nquery UserCalendarEvents($input: UserCalendarEventInput!) {\n  userCalendarEvents(input: $input) {\n    date\n    events {\n      ...CalendarEventPart\n    }\n  }\n}\n\nquery MetadataPartialDetails($metadataId: String!) {\n  metadataPartialDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    image\n    publishYear\n  }\n}\n\nquery UserMetadataGroupsList($input: UserMetadataGroupsListInput!) {\n  userMetadataGroupsList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery UserPeopleList($input: UserPeopleListInput!) {\n  userPeopleList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery UserAccessLinks {\n  userAccessLinks {\n    id\n    name\n    isDemo\n    createdOn\n    expiresOn\n    timesUsed\n    isRevoked\n    maximumUses\n    isAccountDefault\n    isMutationAllowed\n  }\n}\n\nquery ExerciseDetails($exerciseId: String!) {\n  exerciseDetails(exerciseId: $exerciseId) {\n    id\n    lot\n    name\n    level\n    force\n    source\n    muscles\n    mechanic\n    equipment\n    createdByUserId\n    attributes {\n      instructions\n      images\n    }\n  }\n}\n\nquery UserExercisesList($input: UserExercisesListInput!) {\n  userExercisesList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery ImportReports {\n  importReports {\n    id\n    source\n    progress\n    startedOn\n    finishedOn\n    wasSuccess\n    estimatedFinishTime\n    details {\n      import {\n        total\n      }\n      failedItems {\n        lot\n        step\n        error\n        identifier\n      }\n    }\n  }\n}\n\nquery GenresList($input: SearchInput!) {\n  genresList(input: $input) {\n    items\n    details {\n      total\n      nextPage\n    }\n  }\n}\n\nquery GenreDetails($input: GenreDetailsInput!) {\n  genreDetails(input: $input) {\n    details {\n      id\n      name\n      numItems\n    }\n    contents {\n      details {\n        total\n        nextPage\n      }\n      items\n    }\n  }\n}\n\nquery CollectionContents($input: CollectionContentsInput!) {\n  collectionContents(input: $input) {\n    cacheId\n    response {\n      totalItems\n      user {\n        id\n        name\n      }\n      reviews {\n        ...ReviewItemPart\n      }\n      details {\n        name\n        createdOn\n        description\n      }\n      results {\n        details {\n          total\n          nextPage\n        }\n        items {\n          entityId\n          entityLot\n        }\n      }\n    }\n  }\n}\n\nquery CoreDetails {\n  coreDetails {\n    version\n    docsLink\n    pageSize\n    websiteUrl\n    smtpEnabled\n    oidcEnabled\n    signupAllowed\n    repositoryLink\n    disableTelemetry\n    tokenValidForDays\n    localAuthDisabled\n    fileStorageEnabled\n    peopleSearchSources\n    isServerKeyValidated\n    metadataGroupSourceLotMappings {\n      lot\n      source\n    }\n    metadataLotSourceMappings {\n      lot\n      sources\n    }\n    metadataProviderLanguages {\n      source\n      default\n      supported\n    }\n    frontend {\n      url\n      oidcButtonLabel\n      dashboardMessage\n      umami {\n        domains\n        scriptUrl\n        websiteId\n      }\n    }\n    exerciseParameters {\n      lotMapping {\n        lot\n        bests\n      }\n      filters {\n        type\n        level\n        force\n        muscle\n        mechanic\n        equipment\n      }\n    }\n  }\n}\n\nquery MetadataGroupDetails($metadataGroupId: String!) {\n  metadataGroupDetails(metadataGroupId: $metadataGroupId) {\n    contents\n    details {\n      id\n      lot\n      title\n      parts\n      source\n      isPartial\n      sourceUrl\n      identifier\n      description\n      displayImages\n    }\n  }\n}\n\nquery MetadataGroupSearch($input: MetadataGroupSearchInput!) {\n  metadataGroupSearch(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      identifier\n      name\n      image\n      parts\n    }\n  }\n}\n\nquery UserMetadataList($input: UserMetadataListInput!) {\n  userMetadataList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery MetadataSearch($input: MetadataSearchInput!) {\n  metadataSearch(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      identifier\n      title\n      image\n      publishYear\n    }\n  }\n}\n\nquery PeopleSearch($input: PeopleSearchInput!) {\n  peopleSearch(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      identifier\n      name\n      image\n      birthYear\n    }\n  }\n}\n\nquery UserMetadataGroupDetails($metadataGroupId: String!) {\n  userMetadataGroupDetails(metadataGroupId: $metadataGroupId) {\n    recentlyConsumed\n    reviews {\n      ...ReviewItemPart\n    }\n    collections {\n      ...CollectionPart\n    }\n  }\n}\n\nquery UserPersonDetails($personId: String!) {\n  userPersonDetails(personId: $personId) {\n    recentlyConsumed\n    collections {\n      ...CollectionPart\n    }\n    reviews {\n      ...ReviewItemPart\n    }\n  }\n}\n\nquery UserWorkoutDetails($workoutId: String!) {\n  userWorkoutDetails(workoutId: $workoutId) {\n    collections {\n      ...CollectionPart\n    }\n    details {\n      id\n      name\n      endTime\n      duration\n      startTime\n      templateId\n      repeatedFrom\n      caloriesBurnt\n      summary {\n        ...WorkoutSummaryPart\n      }\n      information {\n        ...WorkoutInformationPart\n      }\n    }\n  }\n}\n\nquery UserWorkoutsList($input: UserTemplatesOrWorkoutsListInput!) {\n  userWorkoutsList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery UserWorkoutTemplateDetails($workoutTemplateId: String!) {\n  userWorkoutTemplateDetails(workoutTemplateId: $workoutTemplateId) {\n    collections {\n      ...CollectionPart\n    }\n    details {\n      id\n      name\n      createdOn\n      summary {\n        ...WorkoutSummaryPart\n      }\n      information {\n        ...WorkoutInformationPart\n      }\n    }\n  }\n}\n\nquery UserWorkoutTemplatesList($input: UserTemplatesOrWorkoutsListInput!) {\n  userWorkoutTemplatesList(input: $input) {\n    cacheId\n    response {\n      items\n      details {\n        total\n        nextPage\n      }\n    }\n  }\n}\n\nquery UserAnalyticsParameters {\n  userAnalyticsParameters {\n    endDate\n    startDate\n  }\n}\n\nquery UserPendingNotifications {\n  userPendingNotifications {\n    id\n    message\n    createdOn\n  }\n}": typeof types.GetOidcRedirectUrlDocument,
+    "fragment SeenPodcastExtraInformationPart on SeenPodcastExtraInformation {\n  episode\n}\n\nfragment SeenShowExtraInformationPart on SeenShowExtraInformation {\n  episode\n  season\n}\n\nfragment SeenAnimeExtraInformationPart on SeenAnimeExtraInformation {\n  episode\n}\n\nfragment SeenMangaExtraInformationPart on SeenMangaExtraInformation {\n  volume\n  chapter\n}\n\nfragment CalendarEventPart on GraphqlCalendarEvent {\n  date\n  metadataId\n  metadataLot\n  metadataText\n  metadataImage\n  calendarEventId\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n  animeExtraInformation {\n    ...SeenAnimeExtraInformationPart\n  }\n}\n\nfragment SeenPart on Seen {\n  id\n  state\n  progress\n  reviewId\n  startedOn\n  finishedOn\n  lastUpdatedOn\n  manualTimeSpent\n  numTimesUpdated\n  providerWatchedOn\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n  animeExtraInformation {\n    ...SeenAnimeExtraInformationPart\n  }\n  mangaExtraInformation {\n    ...SeenMangaExtraInformationPart\n  }\n}\n\nfragment MetadataSearchItemPart on MetadataSearchItem {\n  title\n  image\n  identifier\n  publishYear\n}\n\nfragment WorkoutOrExerciseTotalsPart on WorkoutOrExerciseTotals {\n  reps\n  weight\n  distance\n  duration\n  restTime\n  personalBestsAchieved\n}\n\nfragment EntityAssetsPart on EntityAssets {\n  images\n  videos\n}\n\nfragment WorkoutSetStatisticPart on WorkoutSetStatistic {\n  reps\n  pace\n  oneRm\n  weight\n  volume\n  duration\n  distance\n}\n\nfragment WorkoutSetRecordPart on WorkoutSetRecord {\n  lot\n  personalBests\n  statistic {\n    ...WorkoutSetStatisticPart\n  }\n}\n\nfragment WorkoutSummaryPart on WorkoutSummary {\n  total {\n    ...WorkoutOrExerciseTotalsPart\n  }\n  exercises {\n    id\n    lot\n    numSets\n    bestSet {\n      ...WorkoutSetRecordPart\n    }\n  }\n  focused {\n    lots {\n      lot\n      exercises\n    }\n    levels {\n      level\n      exercises\n    }\n    forces {\n      force\n      exercises\n    }\n    muscles {\n      muscle\n      exercises\n    }\n    equipments {\n      equipment\n      exercises\n    }\n  }\n}\n\nfragment CollectionPart on Collection {\n  id\n  name\n  userId\n}\n\nfragment ReviewItemPart on ReviewItem {\n  id\n  rating\n  postedOn\n  isSpoiler\n  visibility\n  textOriginal\n  textRendered\n  seenItemsAssociatedWith\n  postedBy {\n    id\n    name\n  }\n  comments {\n    id\n    text\n    likedBy\n    createdOn\n    user {\n      id\n      name\n    }\n  }\n  showExtraInformation {\n    season\n    episode\n  }\n  podcastExtraInformation {\n    episode\n  }\n  animeExtraInformation {\n    ...SeenAnimeExtraInformationPart\n  }\n  mangaExtraInformation {\n    ...SeenMangaExtraInformationPart\n  }\n}\n\nfragment WorkoutInformationPart on WorkoutInformation {\n  comment\n  assets {\n    ...EntityAssetsPart\n  }\n  supersets {\n    color\n    exercises\n  }\n  exercises {\n    id\n    lot\n    notes\n    total {\n      ...WorkoutOrExerciseTotalsPart\n    }\n    assets {\n      ...EntityAssetsPart\n    }\n    sets {\n      lot\n      rpe\n      note\n      restTime\n      confirmedAt\n      personalBests\n      statistic {\n        ...WorkoutSetStatisticPart\n      }\n    }\n  }\n}\n\nfragment SetRestTimersPart on SetRestTimersSettings {\n  drop\n  warmup\n  normal\n  failure\n}\n\nfragment PersonDetailsGroupedByRolePart on PersonDetailsGroupedByRole {\n  name\n  count\n  items {\n    entityId\n    character\n  }\n}": typeof types.SeenPodcastExtraInformationPartFragmentDoc,
+};
+const documents: Documents = {
     "mutation RegisterUser($input: RegisterUserInput!) {\n  registerUser(input: $input) {\n    __typename\n    ... on RegisterError {\n      error\n    }\n    ... on StringIdObject {\n      id\n    }\n  }\n}\n\nmutation LoginUser($input: AuthUserInput!) {\n  loginUser(input: $input) {\n    __typename\n    ... on LoginError {\n      error\n    }\n    ... on LoginResponse {\n      apiKey\n    }\n  }\n}\n\nmutation AddEntityToCollection($input: ChangeCollectionToEntityInput!) {\n  addEntityToCollection(input: $input)\n}\n\nmutation CommitMetadata($input: CommitMediaInput!) {\n  commitMetadata(input: $input) {\n    id\n  }\n}\n\nmutation CommitMetadataGroup($input: CommitMediaInput!) {\n  commitMetadataGroup(input: $input) {\n    id\n  }\n}\n\nmutation CommitPerson($input: CommitPersonInput!) {\n  commitPerson(input: $input) {\n    id\n  }\n}\n\nmutation CreateCustomExercise($input: ExerciseInput!) {\n  createCustomExercise(input: $input)\n}\n\nmutation UpdateCustomExercise($input: UpdateCustomExerciseInput!) {\n  updateCustomExercise(input: $input)\n}\n\nmutation UpdateUserIntegration($input: UpdateUserIntegrationInput!) {\n  updateUserIntegration(input: $input)\n}\n\nmutation CreateCustomMetadata($input: CreateCustomMetadataInput!) {\n  createCustomMetadata(input: $input) {\n    id\n  }\n}\n\nmutation UpdateCustomMetadata($input: UpdateCustomMetadataInput!) {\n  updateCustomMetadata(input: $input)\n}\n\nmutation CreateOrUpdateCollection($input: CreateOrUpdateCollectionInput!) {\n  createOrUpdateCollection(input: $input) {\n    id\n  }\n}\n\nmutation CreateReviewComment($input: CreateReviewCommentInput!) {\n  createReviewComment(input: $input)\n}\n\nmutation CreateUserMeasurement($input: UserMeasurementInput!) {\n  createUserMeasurement(input: $input)\n}\n\nmutation CreateUserNotificationPlatform($input: CreateUserNotificationPlatformInput!) {\n  createUserNotificationPlatform(input: $input)\n}\n\nmutation CreateUserIntegration($input: CreateUserIntegrationInput!) {\n  createUserIntegration(input: $input) {\n    id\n  }\n}\n\nmutation CreateOrUpdateUserWorkout($input: UserWorkoutInput!) {\n  createOrUpdateUserWorkout(input: $input)\n}\n\nmutation CreateOrUpdateUserWorkoutTemplate($input: UserWorkoutInput!) {\n  createOrUpdateUserWorkoutTemplate(input: $input)\n}\n\nmutation DeleteCollection($collectionName: String!) {\n  deleteCollection(collectionName: $collectionName)\n}\n\nmutation DeleteReview($reviewId: String!) {\n  deleteReview(reviewId: $reviewId)\n}\n\nmutation DeleteS3Object($key: String!) {\n  deleteS3Object(key: $key)\n}\n\nmutation DeleteSeenItem($seenId: String!) {\n  deleteSeenItem(seenId: $seenId) {\n    id\n  }\n}\n\nmutation DeleteUser($toDeleteUserId: String!) {\n  deleteUser(toDeleteUserId: $toDeleteUserId)\n}\n\nmutation DeleteUserIntegration($integrationId: String!) {\n  deleteUserIntegration(integrationId: $integrationId)\n}\n\nmutation DeleteUserMeasurement($timestamp: DateTime!) {\n  deleteUserMeasurement(timestamp: $timestamp)\n}\n\nmutation DeleteUserNotificationPlatform($notificationId: String!) {\n  deleteUserNotificationPlatform(notificationId: $notificationId)\n}\n\nmutation DeleteUserWorkout($workoutId: String!) {\n  deleteUserWorkout(workoutId: $workoutId)\n}\n\nmutation DeleteUserWorkoutTemplate($workoutTemplateId: String!) {\n  deleteUserWorkoutTemplate(workoutTemplateId: $workoutTemplateId)\n}\n\nmutation DeployBackgroundJob($jobName: BackgroundJob!) {\n  deployBackgroundJob(jobName: $jobName)\n}\n\nmutation DeployBulkProgressUpdate($input: [ProgressUpdateInput!]!) {\n  deployBulkProgressUpdate(input: $input)\n}\n\nmutation DeployExportJob {\n  deployExportJob\n}\n\nmutation DeployImportJob($input: DeployImportJobInput!) {\n  deployImportJob(input: $input)\n}\n\nmutation DeployUpdateMetadataJob($metadataId: String!) {\n  deployUpdateMetadataJob(metadataId: $metadataId)\n}\n\nmutation DeployUpdatePersonJob($personId: String!) {\n  deployUpdatePersonJob(personId: $personId)\n}\n\nmutation DeployUpdateMetadataGroupJob($metadataGroupId: String!) {\n  deployUpdateMetadataGroupJob(metadataGroupId: $metadataGroupId)\n}\n\nmutation UpdateSeenItem($input: UpdateSeenItemInput!) {\n  updateSeenItem(input: $input)\n}\n\nmutation UpdateUserNotificationPlatform($input: UpdateUserNotificationPlatformInput!) {\n  updateUserNotificationPlatform(input: $input)\n}\n\nmutation UpdateUserWorkoutAttributes($input: UpdateUserWorkoutAttributesInput!) {\n  updateUserWorkoutAttributes(input: $input)\n}\n\nmutation GenerateAuthToken {\n  generateAuthToken\n}\n\nmutation MergeMetadata($mergeFrom: String!, $mergeInto: String!) {\n  mergeMetadata(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation DisassociateMetadata($metadataId: String!) {\n  disassociateMetadata(metadataId: $metadataId)\n}\n\nmutation CreateOrUpdateReview($input: CreateOrUpdateReviewInput!) {\n  createOrUpdateReview(input: $input) {\n    id\n  }\n}\n\nmutation PresignedPutS3Url($input: PresignedPutUrlInput!) {\n  presignedPutS3Url(input: $input) {\n    key\n    uploadUrl\n  }\n}\n\nmutation RemoveEntityFromCollection($input: ChangeCollectionToEntityInput!) {\n  removeEntityFromCollection(input: $input) {\n    id\n  }\n}\n\nmutation TestUserNotificationPlatforms {\n  testUserNotificationPlatforms\n}\n\nmutation UpdateUser($input: UpdateUserInput!) {\n  updateUser(input: $input) {\n    id\n  }\n}\n\nmutation UpdateUserPreference($input: UserPreferencesInput!) {\n  updateUserPreference(input: $input)\n}\n\nmutation CreateAccessLink($input: CreateAccessLinkInput!) {\n  createAccessLink(input: $input) {\n    id\n  }\n}\n\nmutation ProcessAccessLink($input: ProcessAccessLinkInput!) {\n  processAccessLink(input: $input) {\n    __typename\n    ... on ProcessAccessLinkError {\n      error\n    }\n    ... on ProcessAccessLinkResponse {\n      apiKey\n      redirectTo\n      tokenValidForDays\n    }\n  }\n}\n\nmutation RevokeAccessLink($accessLinkId: String!) {\n  revokeAccessLink(accessLinkId: $accessLinkId)\n}\n\nmutation UpdateUserExerciseSettings($input: UpdateUserExerciseSettings!) {\n  updateUserExerciseSettings(input: $input)\n}\n\nmutation MergeExercise($mergeFrom: String!, $mergeInto: String!) {\n  mergeExercise(mergeFrom: $mergeFrom, mergeInto: $mergeInto)\n}\n\nmutation MarkEntityAsPartial($input: MarkEntityAsPartialInput!) {\n  markEntityAsPartial(input: $input)\n}\n\nmutation MarkNotificationsAsAddressed($notificationIds: [String!]!) {\n  markNotificationsAsAddressed(notificationIds: $notificationIds)\n}\n\nmutation ExpireCacheKey($cacheId: UUID!) {\n  expireCacheKey(cacheId: $cacheId)\n}": types.RegisterUserDocument,
     "query MetadataDetails($metadataId: String!) {\n  metadataDetails(metadataId: $metadataId) {\n    id\n    lot\n    title\n    source\n    isNsfw\n    isPartial\n    sourceUrl\n    identifier\n    description\n    suggestions\n    publishYear\n    publishDate\n    providerRating\n    createdByUserId\n    productionStatus\n    originalLanguage\n    animeSpecifics {\n      episodes\n    }\n    audioBookSpecifics {\n      runtime\n    }\n    movieSpecifics {\n      runtime\n    }\n    genres {\n      id\n      name\n    }\n    group {\n      id\n      name\n      part\n    }\n    watchProviders {\n      name\n      image\n      languages\n    }\n    bookSpecifics {\n      pages\n      isCompilation\n    }\n    mangaSpecifics {\n      volumes\n      chapters\n    }\n    assets {\n      images\n      videos {\n        videoId\n        source\n      }\n    }\n    creators {\n      name\n      items {\n        id\n        name\n        image\n        character\n      }\n    }\n    podcastSpecifics {\n      episodes {\n        id\n        title\n        overview\n        thumbnail\n        number\n        runtime\n        publishDate\n      }\n      totalEpisodes\n    }\n    showSpecifics {\n      totalSeasons\n      totalEpisodes\n      runtime\n      seasons {\n        id\n        seasonNumber\n        name\n        overview\n        backdropImages\n        posterImages\n        episodes {\n          id\n          name\n          posterImages\n          episodeNumber\n          publishDate\n          name\n          overview\n          runtime\n        }\n      }\n    }\n    visualNovelSpecifics {\n      length\n    }\n    videoGameSpecifics {\n      platforms\n    }\n    musicSpecifics {\n      duration\n      viewCount\n      byVariousArtists\n    }\n  }\n}": types.MetadataDetailsDocument,
     "query PersonDetails($personId: String!) {\n  personDetails(personId: $personId) {\n    associatedMetadata {\n      ...PersonDetailsGroupedByRolePart\n    }\n    associatedMetadataGroups {\n      ...PersonDetailsGroupedByRolePart\n    }\n    details {\n      id\n      name\n      place\n      source\n      gender\n      website\n      deathDate\n      birthDate\n      isPartial\n      sourceUrl\n      identifier\n      description\n      displayImages\n      alternateNames\n    }\n  }\n}": types.PersonDetailsDocument,
diff --git a/libs/generated/src/graphql/backend/graphql.ts b/libs/generated/src/graphql/backend/graphql.ts
index e3f303df04..03129bf674 100644
--- a/libs/generated/src/graphql/backend/graphql.ts
+++ b/libs/generated/src/graphql/backend/graphql.ts
@@ -623,6 +623,8 @@ export enum ExerciseLot {
   DistanceAndDuration = 'DISTANCE_AND_DURATION',
   Duration = 'DURATION',
   Reps = 'REPS',
+  RepsAndDuration = 'REPS_AND_DURATION',
+  RepsAndDurationAndDistance = 'REPS_AND_DURATION_AND_DISTANCE',
   RepsAndWeight = 'REPS_AND_WEIGHT'
 }
 
@@ -3014,6 +3016,7 @@ export type WorkoutOrExerciseTotals = {
 
 /** The different types of personal bests that can be achieved on a set. */
 export enum WorkoutSetPersonalBest {
+  Distance = 'DISTANCE',
   OneRm = 'ONE_RM',
   Pace = 'PACE',
   Reps = 'REPS',
diff --git a/libs/generated/src/graphql/backend/types.generated.ts b/libs/generated/src/graphql/backend/types.generated.ts
index b575aa64bb..788b15e25b 100644
--- a/libs/generated/src/graphql/backend/types.generated.ts
+++ b/libs/generated/src/graphql/backend/types.generated.ts
@@ -613,6 +613,8 @@ export enum ExerciseLot {
   DistanceAndDuration = 'DISTANCE_AND_DURATION',
   Duration = 'DURATION',
   Reps = 'REPS',
+  RepsAndDuration = 'REPS_AND_DURATION',
+  RepsAndDurationAndDistance = 'REPS_AND_DURATION_AND_DISTANCE',
   RepsAndWeight = 'REPS_AND_WEIGHT'
 }
 
@@ -3127,6 +3129,7 @@ export type WorkoutOrExerciseTotals = {
 
 /** The different types of personal bests that can be achieved on a set. */
 export enum WorkoutSetPersonalBest {
+  Distance = 'DISTANCE',
   OneRm = 'ONE_RM',
   Pace = 'PACE',
   Reps = 'REPS',


Test patch: