Repository: IgnisDa/ryot (language: rust)

Issue:
[FEATURE REQUEST] - Radarr/Sonarr integration
Hi,
Regarding the exchange on Reddit, i post here an issue as requested to integrate Radarr/Sonarr in the roadmap of ryot.
Best regards


Discussion / hints:
@Nom4 Looking into this. What exactly would an integration with Radarr/Sonarr entail?
Hi, if i remember (i was not using Ryot until this feature was available), the goal is to integrate Radarr/Sonarr as a media source for monitor watching.
Hope i explain well.
I do not think this should be a part of Ryot since it is a media tracker (not monitor). I do not use Radarr/Sonarr myself but I believe the normal flow of using them is Radarr (for monitoring) -> Plex/Jellyfin (for viewing the movie) -> Ryot (for tracking).

Is there any other way you use Radarr/Sonarr?
Hi,My workflow is the following :Overseerr > radarr / sonarr > PlexDid you see ryot in this workflow ?Regards Envoyé de mon iPhoneLe 12 juil. 2023 à 18:54, Diptesh Choudhuri ***@***.***> a écrit :﻿
I do not think this should be a part of Ryot since it is a media tracker (not monitor). I do not use Radarr/Sonarr myself but I believe the normal flow of using them is Radarr (for monitoring) -> Plex/Jellyfin (for viewing the movie) -> Ryot (for tracking).
Is there any other way you use Radarr/Sonarr?

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
Yes looks like you use Plex too. I think it would be better to add integration with it, yes?
Really good idea !Regards 🙏Envoyé de mon iPhoneLe 12 juil. 2023 à 19:28, Diptesh Choudhuri ***@***.***> a écrit :﻿
Yes looks like you use Plex too. I think it would be better to add integration with it, yes?

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
Will create a separate issue for Plex/Jellyfin.
Related to #67.
i would like the ability to add watchlist of movies/tv to radarr/sonarr. right now any time i add something as planning in trakt it auto adds to radarr and sonarr with the use of their "lists." its the big thing keepjng me on trakt for the moment
Are you aware of any open source projects that does something similar? I would like to take a look into their code and see if it is feasible for Ryot.

Moreover can you send me the trakt docs which describe this feature?
https://wiki.servarr.com/sonarr/supported#customimport
https://github.com/noggl/AniPlanrr/

aniplanrr adds shows from anilist to sonarr. they ended up implementing anilist support in sonarr so i dont use this anymore, but it is along the same lines.
I will re-open this issue since it is something Ryot should support. However, I don't plan to work on it since I do not use the *arr services myself. 

Maybe someone else (or a future me) can take this up if they feel like it 😝.
If I understand correctly, the Plex integration doesn't send the IDs of the item you're watching, so it needs to be in the watch list already? Integration with *arr would fundamentally be a way to seed that list, since the media played by Plex is almost guaranteed to be the same media available in *arr. 
I have never used Sonarr/Radarr so I don't know what they do. That's why I haven't gotten around to integrating then.
Short version: You populate them with a list of movies (Radarr) and shows (Sonarr) you're interested in, and a collection of download providers to search. They monitor available releases and download them if they see something matching your selections, either something you don't have or something in a better quality than your current version. Ryot won't care about the downloads at all, just the list of movies/shows the user either has or is interested in having.
So basically Ryot will forward the "Watchlist" collection to *arr instances right?
I would think the it would pull anything in the *arr library into the Watchlist collection, but I'm still trying to get Ryot set up well enough to be sure I'm using the correct terminology.
https://www.reddit.com/r/sonarr/comments/13od1ns/custom_list_in_sonarr/

According to the discussions here, syncing lists to *arr needs an endpoint to just send a list of tvdb Ids:
`[{ "tvdbId": "75837" }, { "tvdbId": "77847" }, { "tvdbId": "78299" }, { "tvdbId": "72756" } ]`
Ryot doesn't have tvdb support (it's paid).
Not really, it's free for anything with less than $50k in revenue but requires attribution: https://thetvdb.com/api-information
Will look into it.

Though TMdb works fine for me so i doubt I'll add tvdb support.
https://developer.themoviedb.org/reference/tv-series-external-ids

This looks promising. Sample output:
`{
  "id": 1399,
  "imdb_id": "tt0944947",
  "freebase_mid": "/m/0524b41",
  "freebase_id": "/en/game_of_thrones",
  "tvdb_id": 121361,
  "tvrage_id": 24493,
  "wikidata_id": "Q23572",
  "facebook_id": "GameOfThrones",
  "instagram_id": "gameofthrones",
  "twitter_id": "GameOfThrones"
}`

I don't know how comprehensive their data is, but should be pretty good I'm assuming.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 4222872041..1a33f08e58 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -455,6 +455,12 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
 [[package]]
 name = "autocfg"
 version = "1.3.0"
@@ -646,13 +652,13 @@ dependencies = [
  "aws-smithy-types",
  "bytes",
  "fastrand",
- "h2",
+ "h2 0.3.26",
  "http 0.2.12",
  "http-body 0.4.6",
  "http-body 1.0.1",
  "httparse",
  "hyper 0.14.30",
- "hyper-rustls",
+ "hyper-rustls 0.24.2",
  "once_cell",
  "pin-project-lite",
  "pin-utils",
@@ -1997,6 +2003,21 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
 [[package]]
 name = "form_urlencoded"
 version = "1.2.1"
@@ -2338,6 +2359,25 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "h2"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http 1.1.0",
+ "indexmap 2.2.6",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
 [[package]]
 name = "handlebars"
 version = "5.1.2"
@@ -2550,7 +2590,7 @@ dependencies = [
  "futures-channel",
  "futures-core",
  "futures-util",
- "h2",
+ "h2 0.3.26",
  "http 0.2.12",
  "http-body 0.4.6",
  "httparse",
@@ -2573,6 +2613,7 @@ dependencies = [
  "bytes",
  "futures-channel",
  "futures-util",
+ "h2 0.4.5",
  "http 1.1.0",
  "http-body 1.0.1",
  "httparse",
@@ -2597,7 +2638,53 @@ dependencies = [
  "rustls 0.21.12",
  "rustls-native-certs",
  "tokio",
- "tokio-rustls",
+ "tokio-rustls 0.24.1",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155"
+dependencies = [
+ "futures-util",
+ "http 1.1.0",
+ "hyper 1.4.1",
+ "hyper-util",
+ "rustls 0.23.11",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls 0.26.0",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper 0.14.30",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper 1.4.1",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
 ]
 
 [[package]]
@@ -3071,6 +3158,23 @@ dependencies = [
  "rand 0.8.5",
 ]
 
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
 [[package]]
 name = "new_debug_unreachable"
 version = "1.0.6"
@@ -3220,19 +3324,57 @@ dependencies = [
  "serde_json",
  "serde_path_to_error",
  "serde_plain",
- "serde_with",
+ "serde_with 3.9.0",
  "sha2",
  "subtle",
  "thiserror",
  "url",
 ]
 
+[[package]]
+name = "openssl"
+version = "0.10.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
 [[package]]
 name = "openssl-probe"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
+[[package]]
+name = "openssl-sys"
+version = "0.9.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "option-ext"
 version = "0.2.0"
@@ -3766,6 +3908,21 @@ version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73"
 
+[[package]]
+name = "radarr-api-rs"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51c70393d7f8bf52eaada85331584091c498d9e2cbbc10935d1c182a81606e6a"
+dependencies = [
+ "reqwest 0.11.27",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_with 2.3.3",
+ "url",
+ "uuid",
+]
+
 [[package]]
 name = "radium"
 version = "0.7.0"
@@ -3963,11 +4120,11 @@ dependencies = [
  "encoding_rs",
  "futures-core",
  "futures-util",
- "h2",
+ "h2 0.3.26",
  "http 0.2.12",
  "http-body 0.4.6",
  "hyper 0.14.30",
- "hyper-rustls",
+ "hyper-rustls 0.24.2",
  "ipnet",
  "js-sys",
  "log",
@@ -3983,7 +4140,7 @@ dependencies = [
  "sync_wrapper 0.1.2",
  "system-configuration",
  "tokio",
- "tokio-rustls",
+ "tokio-rustls 0.24.1",
  "tokio-util",
  "tower-service",
  "url",
@@ -4006,15 +4163,18 @@ dependencies = [
  "encoding_rs",
  "futures-core",
  "futures-util",
- "h2",
+ "h2 0.3.26",
  "http 0.2.12",
  "http-body 0.4.6",
  "hyper 0.14.30",
- "hyper-rustls",
+ "hyper-rustls 0.24.2",
+ "hyper-tls 0.5.0",
  "ipnet",
  "js-sys",
  "log",
  "mime",
+ "mime_guess",
+ "native-tls",
  "once_cell",
  "percent-encoding",
  "pin-project-lite",
@@ -4026,7 +4186,8 @@ dependencies = [
  "sync_wrapper 0.1.2",
  "system-configuration",
  "tokio",
- "tokio-rustls",
+ "tokio-native-tls",
+ "tokio-rustls 0.24.1",
  "tower-service",
  "url",
  "wasm-bindgen",
@@ -4044,26 +4205,35 @@ checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
 dependencies = [
  "base64 0.22.1",
  "bytes",
+ "encoding_rs",
  "futures-channel",
  "futures-core",
  "futures-util",
+ "h2 0.4.5",
  "http 1.1.0",
  "http-body 1.0.1",
  "http-body-util",
  "hyper 1.4.1",
+ "hyper-rustls 0.27.2",
+ "hyper-tls 0.6.0",
  "hyper-util",
  "ipnet",
  "js-sys",
  "log",
  "mime",
+ "mime_guess",
+ "native-tls",
  "once_cell",
  "percent-encoding",
  "pin-project-lite",
+ "rustls-pemfile 2.1.2",
  "serde",
  "serde_json",
  "serde_urlencoded",
  "sync_wrapper 1.0.1",
+ "system-configuration",
  "tokio",
+ "tokio-native-tls",
  "tower-service",
  "url",
  "wasm-bindgen",
@@ -4388,6 +4558,7 @@ dependencies = [
  "nanoid",
  "openidconnect",
  "paginate",
+ "radarr-api-rs",
  "rand 0.9.0-alpha.1",
  "regex",
  "reqwest 0.11.23",
@@ -4403,8 +4574,9 @@ dependencies = [
  "serde",
  "serde-xml-rs",
  "serde_json",
- "serde_with",
+ "serde_with 3.9.0",
  "slug",
+ "sonarr-api-rs",
  "strum",
  "struson",
  "tokio",
@@ -4840,6 +5012,22 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_with"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
+dependencies = [
+ "base64 0.13.1",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "serde",
+ "serde_json",
+ "serde_with_macros 2.3.3",
+ "time",
+]
+
 [[package]]
 name = "serde_with"
 version = "3.9.0"
@@ -4854,10 +5042,22 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "serde_with_macros",
+ "serde_with_macros 3.9.0",
  "time",
 ]
 
+[[package]]
+name = "serde_with_macros"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
 [[package]]
 name = "serde_with_macros"
 version = "3.9.0"
@@ -5021,6 +5221,20 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "sonarr-api-rs"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0f85e838c6093957978793ece2c0893c838da8dd5bcab0ff6f57fcaa8fc8ee9"
+dependencies = [
+ "reqwest 0.12.5",
+ "serde",
+ "serde_json",
+ "serde_with 3.9.0",
+ "url",
+ "uuid",
+]
+
 [[package]]
 name = "spin"
 version = "0.9.8"
@@ -5615,6 +5829,16 @@ dependencies = [
  "syn 2.0.72",
 ]
 
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-retry"
 version = "0.3.0"
@@ -5636,6 +5860,17 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls 0.23.11",
+ "rustls-pki-types",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-stream"
 version = "0.1.15"
diff --git a/apps/backend/Cargo.toml b/apps/backend/Cargo.toml
index 0e4f72ad02..b535988553 100644
--- a/apps/backend/Cargo.toml
+++ b/apps/backend/Cargo.toml
@@ -54,6 +54,7 @@ mime_guess = "=2.0.5"
 nanoid = { workspace = true }
 openidconnect = "=3.5.0"
 paginate = "=1.1.11"
+radarr-api-rs = "=3.0.1"
 rand = "=0.9.0-alpha.1"
 regex = "=1.10.5"
 # FIXME: Upgrade once https://github.com/seanmonstar/reqwest/pull/1620 is merged
@@ -76,6 +77,7 @@ serde_json = { workspace = true }
 serde_with = { version = "=3.9.0", features = ["chrono_0_4"] }
 serde-xml-rs = "=0.6.0"
 slug = "=0.1.5"
+sonarr-api-rs = "=3.0.0"
 strum = { workspace = true }
 struson = { version = "=0.5.0", features = ["serde"] }
 tokio = { version = "=1.38.1", features = ["full"] }
diff --git a/apps/backend/src/background.rs b/apps/backend/src/background.rs
index 3fe3618483..56dc2754b9 100644
--- a/apps/backend/src/background.rs
+++ b/apps/backend/src/background.rs
@@ -41,12 +41,17 @@ pub async fn background_jobs(
     Ok(())
 }
 
-pub async fn yank_integrations_data(
+pub async fn sync_integrations_data(
     _information: ScheduledJob,
     misc_service: Data<Arc<MiscellaneousService>>,
 ) -> Result<(), Error> {
     tracing::trace!("Getting data from yanked integrations for all users");
     misc_service.yank_integrations_data().await.unwrap();
+    tracing::trace!("Sending data for push integrations for all users");
+    misc_service
+        .send_data_for_push_integrations()
+        .await
+        .unwrap();
     Ok(())
 }
 
@@ -55,7 +60,7 @@ pub async fn yank_integrations_data(
 // The background jobs which cannot be throttled.
 #[derive(Debug, Deserialize, Serialize, Display)]
 pub enum CoreApplicationJob {
-    YankIntegrationsData(String),
+    SyncIntegrationsData(String),
     BulkProgressUpdate(String, Vec<ProgressUpdateInput>),
 }
 
@@ -71,10 +76,16 @@ pub async fn perform_core_application_job(
     tracing::trace!("Started job: {:#?}", name);
     let start = Instant::now();
     let status = match information {
-        CoreApplicationJob::YankIntegrationsData(user_id) => misc_service
-            .yank_integrations_data_for_user(&user_id)
-            .await
-            .is_ok(),
+        CoreApplicationJob::SyncIntegrationsData(user_id) => {
+            misc_service
+                .push_integrations_data_for_user(&user_id)
+                .await
+                .ok();
+            misc_service
+                .yank_integrations_data_for_user(&user_id)
+                .await
+                .is_ok()
+        }
         CoreApplicationJob::BulkProgressUpdate(user_id, input) => misc_service
             .bulk_progress_update(user_id, input)
             .await
diff --git a/apps/backend/src/entities/collection_to_entity.rs b/apps/backend/src/entities/collection_to_entity.rs
index 6cb3834d71..ecf442e9b0 100644
--- a/apps/backend/src/entities/collection_to_entity.rs
+++ b/apps/backend/src/entities/collection_to_entity.rs
@@ -5,6 +5,8 @@ use sea_orm::entity::prelude::*;
 use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 
+use crate::models::CollectionToEntitySystemInformation;
+
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
 #[sea_orm(table_name = "collection_to_entity")]
 pub struct Model {
@@ -21,6 +23,8 @@ pub struct Model {
     pub exercise_id: Option<String>,
     pub workout_id: Option<String>,
     pub information: Option<serde_json::Value>,
+    #[sea_orm(column_type = "Json")]
+    pub system_information: CollectionToEntitySystemInformation,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/apps/backend/src/entities/integration.rs b/apps/backend/src/entities/integration.rs
index ed9a1ecc54..f9aec10cf2 100644
--- a/apps/backend/src/entities/integration.rs
+++ b/apps/backend/src/entities/integration.rs
@@ -2,11 +2,11 @@
 
 use async_graphql::{InputObject, SimpleObject};
 use async_trait::async_trait;
-use database::{IntegrationLot, IntegrationSource};
+use database::{IntegrationLot, IntegrationProvider};
 use nanoid::nanoid;
 use sea_orm::{entity::prelude::*, ActiveValue};
 
-use crate::models::media::IntegrationSourceSpecifics;
+use crate::models::media::IntegrationProviderSpecifics;
 
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject, InputObject)]
 #[sea_orm(table_name = "integration")]
@@ -15,19 +15,20 @@ pub struct Model {
     #[sea_orm(primary_key, auto_increment = false)]
     #[graphql(skip_input)]
     pub id: String,
-    pub minimum_progress: Decimal,
-    pub maximum_progress: Decimal,
+    pub minimum_progress: Option<Decimal>,
+    pub maximum_progress: Option<Decimal>,
     #[graphql(skip)]
     pub user_id: String,
     pub lot: IntegrationLot,
-    pub source: IntegrationSource,
+    pub provider: IntegrationProvider,
     pub is_disabled: Option<bool>,
     #[graphql(skip_input)]
     pub created_on: DateTimeUtc,
     #[graphql(skip_input)]
     pub last_triggered_on: Option<DateTimeUtc>,
     #[sea_orm(column_type = "Json")]
-    pub source_specifics: Option<IntegrationSourceSpecifics>,
+    #[graphql(skip)]
+    pub provider_specifics: Option<IntegrationProviderSpecifics>,
 }
 
 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
diff --git a/apps/backend/src/entities/metadata.rs b/apps/backend/src/entities/metadata.rs
index b3a5729641..d0a3a7204a 100644
--- a/apps/backend/src/entities/metadata.rs
+++ b/apps/backend/src/entities/metadata.rs
@@ -9,9 +9,9 @@ use sea_orm::{entity::prelude::*, ActiveValue};
 use serde::{Deserialize, Serialize};
 
 use crate::models::media::{
-    AnimeSpecifics, AudioBookSpecifics, BookSpecifics, MangaSpecifics, MetadataFreeCreator,
-    MetadataImage, MetadataStateChanges, MetadataVideo, MovieSpecifics, PodcastSpecifics,
-    ShowSpecifics, VideoGameSpecifics, VisualNovelSpecifics, WatchProvider,
+    AnimeSpecifics, AudioBookSpecifics, BookSpecifics, ExternalIdentifiers, MangaSpecifics,
+    MetadataFreeCreator, MetadataImage, MetadataStateChanges, MetadataVideo, MovieSpecifics,
+    PodcastSpecifics, ShowSpecifics, VideoGameSpecifics, VisualNovelSpecifics, WatchProvider,
 };
 
 #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize, Default)]
@@ -41,6 +41,8 @@ pub struct Model {
     pub free_creators: Option<Vec<MetadataFreeCreator>>,
     #[sea_orm(column_type = "Json")]
     pub watch_providers: Option<Vec<WatchProvider>>,
+    #[sea_orm(column_type = "Json")]
+    pub external_identifiers: Option<ExternalIdentifiers>,
     pub audio_book_specifics: Option<AudioBookSpecifics>,
     pub book_specifics: Option<BookSpecifics>,
     pub movie_specifics: Option<MovieSpecifics>,
diff --git a/apps/backend/src/integrations.rs b/apps/backend/src/integrations.rs
index 5fb2cf3980..41ffb097bf 100644
--- a/apps/backend/src/integrations.rs
+++ b/apps/backend/src/integrations.rs
@@ -3,6 +3,13 @@ use std::future::Future;
 use anyhow::{anyhow, bail, Result};
 use async_graphql::Result as GqlResult;
 use database::{MediaLot, MediaSource};
+use radarr_api_rs::{
+    apis::{
+        configuration::{ApiKey as RadarrApiKey, Configuration as RadarrConfiguration},
+        movie_api::api_v3_movie_post as radarr_api_v3_movie_post,
+    },
+    models::{AddMovieOptions as RadarrAddMovieOptions, MovieResource as RadarrMovieResource},
+};
 use regex::Regex;
 use reqwest::header::{HeaderValue, AUTHORIZATION};
 use rust_decimal::Decimal;
@@ -10,11 +17,19 @@ use rust_decimal_macros::dec;
 use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter};
 use sea_query::{extension::postgres::PgExpr, Alias, Expr, Func};
 use serde::{Deserialize, Serialize};
+use sonarr_api_rs::{
+    apis::{
+        configuration::{ApiKey as SonarrApiKey, Configuration as SonarrConfiguration},
+        series_api::api_v3_series_post as sonarr_api_v3_series_post,
+    },
+    models::{AddSeriesOptions as SonarrAddSeriesOptions, SeriesResource as SonarrSeriesResource},
+};
 
 use crate::{
     entities::{metadata, prelude::Metadata},
     models::{audiobookshelf_models, media::CommitMediaInput},
     providers::google_books::GoogleBooksService,
+    traits::TraceOk,
     utils::{get_base_http_client, ilike_sql},
 };
 
@@ -517,4 +532,62 @@ impl IntegrationService {
         }
         Ok((media_items, vec![]))
     }
+
+    pub async fn radarr_push(
+        &self,
+        radarr_base_url: String,
+        radarr_api_key: String,
+        radarr_profile_id: i32,
+        radarr_root_folder_path: String,
+        tmdb_id: String,
+    ) -> Result<()> {
+        let mut configuration = RadarrConfiguration::new();
+        configuration.base_path = radarr_base_url;
+        configuration.api_key = Some(RadarrApiKey {
+            key: radarr_api_key,
+            prefix: None,
+        });
+        let mut resource = RadarrMovieResource::new();
+        resource.tmdb_id = Some(tmdb_id.parse().unwrap());
+        resource.quality_profile_id = Some(radarr_profile_id);
+        resource.root_folder_path = Some(Some(radarr_root_folder_path.clone()));
+        resource.monitored = Some(true);
+        let mut options = RadarrAddMovieOptions::new();
+        options.search_for_movie = Some(true);
+        resource.add_options = Some(Box::new(options));
+        radarr_api_v3_movie_post(&configuration, Some(resource))
+            .await
+            .trace_ok();
+        Ok(())
+    }
+
+    pub async fn sonarr_push(
+        &self,
+        sonarr_base_url: String,
+        sonarr_api_key: String,
+        sonarr_profile_id: i32,
+        sonarr_root_folder_path: String,
+        tvdb_id: String,
+    ) -> Result<()> {
+        let mut configuration = SonarrConfiguration::new();
+        configuration.base_path = sonarr_base_url;
+        configuration.api_key = Some(SonarrApiKey {
+            key: sonarr_api_key,
+            prefix: None,
+        });
+        let mut resource = SonarrSeriesResource::new();
+        resource.title = Some(Some(tvdb_id.clone()));
+        resource.tvdb_id = Some(tvdb_id.parse().unwrap());
+        resource.quality_profile_id = Some(sonarr_profile_id);
+        resource.root_folder_path = Some(Some(sonarr_root_folder_path.clone()));
+        resource.monitored = Some(true);
+        resource.season_folder = Some(true);
+        let mut options = SonarrAddSeriesOptions::new();
+        options.search_for_missing_episodes = Some(true);
+        resource.add_options = Some(Box::new(options));
+        sonarr_api_v3_series_post(&configuration, Some(resource))
+            .await
+            .trace_ok();
+        Ok(())
+    }
 }
diff --git a/apps/backend/src/main.rs b/apps/backend/src/main.rs
index dda502683d..0470753769 100644
--- a/apps/backend/src/main.rs
+++ b/apps/backend/src/main.rs
@@ -48,7 +48,7 @@ use utils::{COMPILATION_TIMESTAMP, TEMP_DIR};
 use crate::{
     background::{
         background_jobs, perform_application_job, perform_core_application_job,
-        yank_integrations_data,
+        sync_integrations_data,
     },
     entities::prelude::Exercise,
     graphql::get_schema,
@@ -102,7 +102,7 @@ async fn main() -> Result<()> {
         .map(|f| f.parse().unwrap())
         .collect_vec();
     let rate_limit_count = config.scheduler.rate_limit_num;
-    let pull_every_minutes = config.integration.pull_every_minutes;
+    let sync_every_minutes = config.integration.sync_every_minutes;
     let max_file_size = config.server.max_file_size;
     let disable_background_jobs = config.server.disable_background_jobs;
 
@@ -273,10 +273,10 @@ async fn main() -> Result<()> {
             )
             .register_with_count(
                 1,
-                WorkerBuilder::new("yank_integrations_data")
+                WorkerBuilder::new("sync_integrations_data")
                     .stream(
                         CronStream::new_with_timezone(
-                            Schedule::from_str(&format!("0 */{} * * * *", pull_every_minutes))
+                            Schedule::from_str(&format!("0 */{} * * * *", sync_every_minutes))
                                 .unwrap(),
                             tz,
                         )
@@ -284,7 +284,7 @@ async fn main() -> Result<()> {
                     )
                     .layer(ApalisTraceLayer::new())
                     .data(media_service_3.clone())
-                    .build_fn(yank_integrations_data),
+                    .build_fn(sync_integrations_data),
             )
             // application jobs
             .register_with_count(
diff --git a/apps/backend/src/miscellaneous.rs b/apps/backend/src/miscellaneous.rs
index 9bf963824f..4167dfcb5f 100644
--- a/apps/backend/src/miscellaneous.rs
+++ b/apps/backend/src/miscellaneous.rs
@@ -1,12 +1,14 @@
 use std::{
     collections::{HashMap, HashSet},
     fs::File,
+    future::Future,
     iter::zip,
     path::PathBuf,
     str::FromStr,
     sync::Arc,
 };
 
+use anyhow::Result as AnyhowResult;
 use apalis::prelude::{MemoryStorage, MessageQueue};
 use argon2::{Argon2, PasswordHash, PasswordVerifier};
 use async_graphql::{
@@ -17,7 +19,7 @@ use chrono::{Days, Duration as ChronoDuration, NaiveDate, Utc};
 use database::{
     AliasedCollection, AliasedCollectionToEntity, AliasedExercise, AliasedMetadata,
     AliasedMetadataGroup, AliasedMetadataToGenre, AliasedPerson, AliasedSeen, AliasedUser,
-    AliasedUserToCollection, AliasedUserToEntity, EntityLot, IntegrationLot, IntegrationSource,
+    AliasedUserToCollection, AliasedUserToEntity, EntityLot, IntegrationLot, IntegrationProvider,
     MediaLot, MediaSource, MetadataToMetadataRelation, NotificationPlatformLot, SeenState, UserLot,
     UserToMediaReason, Visibility,
 };
@@ -77,7 +79,7 @@ use crate::{
             CreateOrUpdateCollectionInput, EntityWithLot, GenreListItem, ImportOrExportItemRating,
             ImportOrExportItemReview, ImportOrExportItemReviewComment,
             ImportOrExportMediaGroupItem, ImportOrExportMediaItem, ImportOrExportMediaItemSeen,
-            ImportOrExportPersonItem, IntegrationSourceSpecifics, MangaSpecifics,
+            ImportOrExportPersonItem, IntegrationProviderSpecifics, MangaSpecifics,
             MediaAssociatedPersonStateChanges, MediaDetails, MetadataFreeCreator,
             MetadataGroupSearchItem, MetadataImage, MetadataImageForMediaDetails,
             MetadataPartialDetails, MetadataSearchItemResponse, MetadataVideo, MetadataVideoSource,
@@ -89,8 +91,9 @@ use crate::{
             ShowSpecifics, VideoGameSpecifics, VisualNovelSpecifics, WatchProvider,
         },
         BackendError, BackgroundJob, ChangeCollectionToEntityInput, CollectionExtraInformation,
-        DefaultCollection, IdAndNamedObject, MediaStateChanged, SearchDetails, SearchInput,
-        SearchResults, StoredUrl, StringIdObject, UserSummaryData,
+        CollectionToEntitySystemInformation, DefaultCollection, IdAndNamedObject,
+        MediaStateChanged, SearchDetails, SearchInput, SearchResults, StoredUrl, StringIdObject,
+        UserSummaryData,
     },
     providers::{
         anilist::{
@@ -148,10 +151,10 @@ struct CreateCustomMetadataInput {
 
 #[derive(Debug, Serialize, Deserialize, InputObject, Clone)]
 struct CreateUserIntegrationInput {
-    source: IntegrationSource,
-    source_specifics: Option<IntegrationSourceSpecifics>,
-    minimum_progress: Decimal,
-    maximum_progress: Decimal,
+    provider: IntegrationProvider,
+    provider_specifics: Option<IntegrationProviderSpecifics>,
+    minimum_progress: Option<Decimal>,
+    maximum_progress: Option<Decimal>,
 }
 
 #[derive(Debug, Serialize, Deserialize, InputObject, Clone)]
@@ -2639,9 +2642,9 @@ impl MiscellaneousService {
                     .await
                     .unwrap();
             }
-            BackgroundJob::YankIntegrationsData => {
+            BackgroundJob::SyncIntegrationsData => {
                 core_sqlite_storage
-                    .enqueue(CoreApplicationJob::YankIntegrationsData(user_id.to_owned()))
+                    .enqueue(CoreApplicationJob::SyncIntegrationsData(user_id.to_owned()))
                     .await
                     .unwrap();
             }
@@ -2999,6 +3002,7 @@ impl MiscellaneousService {
         meta.book_specifics = ActiveValue::Set(input.book_specifics);
         meta.video_game_specifics = ActiveValue::Set(input.video_game_specifics);
         meta.visual_novel_specifics = ActiveValue::Set(input.visual_novel_specifics);
+        meta.external_identifiers = ActiveValue::Set(input.external_identifiers);
         let metadata = meta.update(&self.db).await.unwrap();
 
         self.change_metadata_associations(
@@ -3220,6 +3224,7 @@ impl MiscellaneousService {
             provider_rating: ActiveValue::Set(details.provider_rating),
             production_status: ActiveValue::Set(details.production_status),
             original_language: ActiveValue::Set(details.original_language),
+            external_identifiers: ActiveValue::Set(details.external_identifiers),
             is_nsfw: ActiveValue::Set(details.is_nsfw),
             is_partial: ActiveValue::Set(is_partial),
             free_creators: ActiveValue::Set(if details.creators.is_empty() {
@@ -5421,8 +5426,8 @@ impl MiscellaneousService {
                             }
                             preferences.general.dashboard = value;
                         }
-                        "disable_yank_integrations" => {
-                            preferences.general.disable_yank_integrations = value_bool.unwrap();
+                        "disable_integrations" => {
+                            preferences.general.disable_integrations = value_bool.unwrap();
                         }
                         "persist_queries" => {
                             preferences.general.persist_queries = value_bool.unwrap();
@@ -5484,17 +5489,18 @@ impl MiscellaneousService {
                 "Minimum progress cannot be greater than maximum progress",
             ));
         }
-        let lot = match input.source {
-            IntegrationSource::Audiobookshelf => IntegrationLot::Yank,
+        let lot = match input.provider {
+            IntegrationProvider::Audiobookshelf => IntegrationLot::Yank,
+            IntegrationProvider::Radarr | IntegrationProvider::Sonarr => IntegrationLot::Push,
             _ => IntegrationLot::Sink,
         };
         let to_insert = integration::ActiveModel {
             lot: ActiveValue::Set(lot),
             user_id: ActiveValue::Set(user_id),
-            source: ActiveValue::Set(input.source),
-            source_specifics: ActiveValue::Set(input.source_specifics),
+            provider: ActiveValue::Set(input.provider),
             minimum_progress: ActiveValue::Set(input.minimum_progress),
             maximum_progress: ActiveValue::Set(input.maximum_progress),
+            provider_specifics: ActiveValue::Set(input.provider_specifics),
             ..Default::default()
         };
         let integration = to_insert.insert(&self.db).await?;
@@ -5520,10 +5526,10 @@ impl MiscellaneousService {
         }
         let mut db_integration: integration::ActiveModel = db_integration.into();
         if let Some(s) = input.minimum_progress {
-            db_integration.minimum_progress = ActiveValue::Set(s);
+            db_integration.minimum_progress = ActiveValue::Set(Some(s));
         }
         if let Some(s) = input.maximum_progress {
-            db_integration.maximum_progress = ActiveValue::Set(s);
+            db_integration.maximum_progress = ActiveValue::Set(Some(s));
         }
         if let Some(d) = input.is_disabled {
             db_integration.is_disabled = ActiveValue::Set(Some(d));
@@ -5734,7 +5740,7 @@ impl MiscellaneousService {
 
     pub async fn yank_integrations_data_for_user(&self, user_id: &String) -> Result<bool> {
         let preferences = self.user_preferences(user_id).await?;
-        if preferences.general.disable_yank_integrations {
+        if preferences.general.disable_integrations {
             return Ok(false);
         }
         let integrations = Integration::find()
@@ -5744,15 +5750,16 @@ impl MiscellaneousService {
         let mut progress_updates = vec![];
         let mut collection_updates = vec![];
         let mut to_update_integrations = vec![];
+        let integration_service = self.get_integration_service();
         for integration in integrations.into_iter() {
             if integration.is_disabled.unwrap_or_default() {
                 tracing::debug!("Integration {} is disabled", integration.id);
                 continue;
             }
-            let response = match integration.source {
-                IntegrationSource::Audiobookshelf => {
-                    let specifics = integration.clone().source_specifics.unwrap();
-                    self.get_integration_service()
+            let response = match integration.provider {
+                IntegrationProvider::Audiobookshelf => {
+                    let specifics = integration.clone().provider_specifics.unwrap();
+                    integration_service
                         .audiobookshelf_progress(
                             &specifics.audiobookshelf_base_url.unwrap(),
                             &specifics.audiobookshelf_token.unwrap(),
@@ -5823,6 +5830,153 @@ impl MiscellaneousService {
         Ok(())
     }
 
+    pub async fn send_data_for_push_integrations(&self) -> Result<()> {
+        let users_with_integrations = Integration::find()
+            .filter(integration::Column::Lot.eq(IntegrationLot::Push))
+            .select_only()
+            .column(integration::Column::UserId)
+            .into_tuple::<String>()
+            .all(&self.db)
+            .await?;
+        for user_id in users_with_integrations {
+            tracing::debug!("Pushing integrations data for user {}", user_id);
+            self.push_integrations_data_for_user(&user_id).await?;
+        }
+        Ok(())
+    }
+
+    pub async fn push_integrations_data_for_user(&self, user_id: &String) -> Result<bool> {
+        let preferences = self.user_preferences(user_id).await?;
+        if preferences.general.disable_integrations {
+            return Ok(false);
+        }
+        let integrations = Integration::find()
+            .filter(integration::Column::UserId.eq(user_id))
+            .all(&self.db)
+            .await?;
+        #[allow(clippy::too_many_arguments)]
+        async fn push_data_to_arr_service<F>(
+            db: &DatabaseConnection,
+            integration: integration::Model,
+            lot: MediaLot,
+            get_collection_ids: impl Fn(IntegrationProviderSpecifics) -> Vec<String>,
+            skip_in: impl Fn(CollectionToEntitySystemInformation) -> Option<Vec<String>>,
+            get_identifier: impl Fn(metadata::Model) -> Option<String>,
+            perform_push: impl Fn(String, IntegrationProviderSpecifics) -> F,
+            column_name: &str,
+        ) -> Result<()>
+        where
+            F: Future<Output = AnyhowResult<()>>,
+        {
+            let specifics = integration.provider_specifics.unwrap();
+            let collection_ids = get_collection_ids(specifics.clone());
+            let tmdb_ids_to_add = CollectionToEntity::find()
+                .find_also_related(Metadata)
+                .filter(metadata::Column::Lot.eq(lot))
+                .filter(metadata::Column::Source.eq(MediaSource::Tmdb))
+                .filter(collection_to_entity::Column::CollectionId.is_in(collection_ids))
+                .all(db)
+                .await?;
+            let mut cte_to_update = vec![];
+            for (cte, metadata) in tmdb_ids_to_add {
+                let metadata = metadata.unwrap();
+                if skip_in(cte.system_information)
+                    .unwrap_or_default()
+                    .contains(&integration.id)
+                {
+                    tracing::debug!("{} {} is already synced", lot, metadata.title);
+                    continue;
+                }
+                if let Some(entity_identifier) = get_identifier(metadata) {
+                    perform_push(entity_identifier, specifics.clone())
+                        .await
+                        .ok();
+                    cte_to_update.push(cte.id);
+                }
+            }
+            CollectionToEntity::update_many()
+                        .filter(collection_to_entity::Column::Id.is_in(cte_to_update))
+                        .col_expr(
+                            collection_to_entity::Column::SystemInformation,
+                            Expr::cust(
+                                format!(
+                                    r#"JSONB_SET(system_information, '{{{col}}}', COALESCE(system_information->'{col}','[]'::JSONB) || '["{id}"]'::JSONB)"#,
+                                    col = column_name,
+                                    id = &integration.id
+                                )
+                            ),
+                        )
+                        .exec(db)
+                        .await?;
+            Ok(())
+        }
+        let mut to_update_integrations = vec![];
+        let integration_service = self.get_integration_service();
+        for integration in integrations.into_iter() {
+            let id = integration.id.clone();
+            match integration.provider {
+                IntegrationProvider::Radarr => {
+                    push_data_to_arr_service(
+                        &self.db,
+                        integration,
+                        MediaLot::Movie,
+                        |specifics| specifics.radarr_sync_collection_ids.unwrap(),
+                        |info| info.radarr_synced,
+                        |m| Some(m.identifier),
+                        |entity_tmdb_id, specifics| {
+                            integration_service.radarr_push(
+                                specifics.radarr_base_url.unwrap(),
+                                specifics.radarr_api_key.unwrap(),
+                                specifics.radarr_profile_id.unwrap(),
+                                specifics.radarr_root_folder_path.unwrap(),
+                                entity_tmdb_id,
+                            )
+                        },
+                        "radarr_synced",
+                    )
+                    .await
+                    .ok();
+                }
+                IntegrationProvider::Sonarr => {
+                    push_data_to_arr_service(
+                        &self.db,
+                        integration,
+                        MediaLot::Show,
+                        |specifics| specifics.sonarr_sync_collection_ids.unwrap(),
+                        |info| info.sonarr_synced,
+                        |m| {
+                            m.external_identifiers
+                                .and_then(|i| i.tvdb_id.map(|s| s.to_string()))
+                        },
+                        |entity_tmdb_id, specifics| {
+                            integration_service.sonarr_push(
+                                specifics.sonarr_base_url.unwrap(),
+                                specifics.sonarr_api_key.unwrap(),
+                                specifics.sonarr_profile_id.unwrap(),
+                                specifics.sonarr_root_folder_path.unwrap(),
+                                entity_tmdb_id,
+                            )
+                        },
+                        "sonarr_synced",
+                    )
+                    .await
+                    .ok();
+                }
+                _ => continue,
+            };
+            to_update_integrations.push(id);
+        }
+        Integration::update_many()
+            .filter(integration::Column::Id.is_in(to_update_integrations))
+            .col_expr(
+                integration::Column::LastTriggeredOn,
+                Expr::value(Utc::now()),
+            )
+            .exec(&self.db)
+            .await?;
+        Ok(true)
+    }
+
     async fn admin_account_guard(&self, user_id: &String) -> Result<()> {
         let main_user = user_by_id(&self.db, user_id).await?;
         if main_user.lot != UserLot::Admin {
@@ -5877,16 +6031,17 @@ impl MiscellaneousService {
             .one(&self.db)
             .await?
             .ok_or_else(|| Error::new("Integration does not exist".to_owned()))?;
-        if integration.is_disabled.unwrap_or_default() {
+        let preferences = self.user_preferences(&integration.user_id).await?;
+        if integration.is_disabled.unwrap_or_default() || preferences.general.disable_integrations {
             return Err(Error::new("Integration is disabled".to_owned()));
         }
         let service = self.get_integration_service();
-        let maybe_progress_update = match integration.source {
-            IntegrationSource::Kodi => service.kodi_progress(&payload).await,
-            IntegrationSource::Emby => service.emby_progress(&payload).await,
-            IntegrationSource::Jellyfin => service.jellyfin_progress(&payload).await,
-            IntegrationSource::Plex => {
-                let specifics = integration.clone().source_specifics.unwrap();
+        let maybe_progress_update = match integration.provider {
+            IntegrationProvider::Kodi => service.kodi_progress(&payload).await,
+            IntegrationProvider::Emby => service.emby_progress(&payload).await,
+            IntegrationProvider::Jellyfin => service.jellyfin_progress(&payload).await,
+            IntegrationProvider::Plex => {
+                let specifics = integration.clone().provider_specifics.unwrap();
                 service
                     .plex_progress(&payload, specifics.plex_username)
                     .await
@@ -5913,10 +6068,10 @@ impl MiscellaneousService {
         pu: IntegrationMediaSeen,
         user_id: &String,
     ) -> Result<()> {
-        if pu.progress < integration.minimum_progress {
+        if pu.progress < integration.minimum_progress.unwrap() {
             return Ok(());
         }
-        let progress = if pu.progress > integration.maximum_progress {
+        let progress = if pu.progress > integration.maximum_progress.unwrap() {
             dec!(100)
         } else {
             pu.progress
@@ -6090,12 +6245,11 @@ impl MiscellaneousService {
 
             let min_value = values.iter().min();
             let max_value = values.iter().max();
-            let is_complete = match (min_value, max_value) {
+
+            match (min_value, max_value) {
                 (Some(min), Some(max)) => min == max && *min != 0,
                 _ => false,
-            };
-
-            is_complete
+            }
         } else {
             seen_history.iter().any(|h| h.state == SeenState::Completed)
         };
diff --git a/apps/backend/src/models.rs b/apps/backend/src/models.rs
index 2de0e8d7e0..1af78bcdc2 100644
--- a/apps/backend/src/models.rs
+++ b/apps/backend/src/models.rs
@@ -108,6 +108,12 @@ meta! {
     ), "Items that I want to be reminded about.");
 }
 
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, FromJsonQueryResult)]
+pub struct CollectionToEntitySystemInformation {
+    pub radarr_synced: Option<Vec<String>>,
+    pub sonarr_synced: Option<Vec<String>>,
+}
+
 #[derive(Enum, Serialize, Deserialize, Clone, Debug, Copy, PartialEq, Eq)]
 pub enum BackgroundJob {
     CalculateSummary,
@@ -115,7 +121,7 @@ pub enum BackgroundJob {
     UpdateAllMetadata,
     UpdateAllExercises,
     RecalculateCalendarEvents,
-    YankIntegrationsData,
+    SyncIntegrationsData,
     PerformBackgroundTasks,
 }
 
@@ -880,6 +886,21 @@ pub mod media {
         pub languages: HashSet<String>,
     }
 
+    #[derive(
+        Clone,
+        Debug,
+        PartialEq,
+        FromJsonQueryResult,
+        Eq,
+        Serialize,
+        Deserialize,
+        SimpleObject,
+        Default,
+    )]
+    pub struct ExternalIdentifiers {
+        pub tvdb_id: Option<i32>,
+    }
+
     #[derive(Debug, Serialize, Deserialize, Clone, Default)]
     pub struct MediaDetails {
         pub identifier: String,
@@ -904,6 +925,7 @@ pub mod media {
         pub watch_providers: Vec<WatchProvider>,
         pub audio_book_specifics: Option<AudioBookSpecifics>,
         pub book_specifics: Option<BookSpecifics>,
+        pub external_identifiers: Option<ExternalIdentifiers>,
         pub movie_specifics: Option<MovieSpecifics>,
         pub podcast_specifics: Option<PodcastSpecifics>,
         pub show_specifics: Option<ShowSpecifics>,
@@ -1285,10 +1307,20 @@ pub mod media {
     )]
     #[graphql(input_name = "IntegrationSourceSpecificsInput")]
     #[serde(rename_all = "snake_case")]
-    pub struct IntegrationSourceSpecifics {
+    pub struct IntegrationProviderSpecifics {
         pub plex_username: Option<String>,
         pub audiobookshelf_base_url: Option<String>,
         pub audiobookshelf_token: Option<String>,
+        pub radarr_base_url: Option<String>,
+        pub radarr_api_key: Option<String>,
+        pub radarr_profile_id: Option<i32>,
+        pub radarr_root_folder_path: Option<String>,
+        pub radarr_sync_collection_ids: Option<Vec<String>>,
+        pub sonarr_base_url: Option<String>,
+        pub sonarr_api_key: Option<String>,
+        pub sonarr_profile_id: Option<i32>,
+        pub sonarr_root_folder_path: Option<String>,
+        pub sonarr_sync_collection_ids: Option<Vec<String>>,
     }
 }
 
diff --git a/apps/backend/src/providers/tmdb.rs b/apps/backend/src/providers/tmdb.rs
index 7e0e8fe74b..718f2071d6 100644
--- a/apps/backend/src/providers/tmdb.rs
+++ b/apps/backend/src/providers/tmdb.rs
@@ -26,10 +26,11 @@ use crate::{
     entities::metadata_group::MetadataGroupWithoutId,
     models::{
         media::{
-            MediaDetails, MetadataGroupSearchItem, MetadataImage, MetadataImageForMediaDetails,
-            MetadataPerson, MetadataSearchItem, MetadataVideo, MetadataVideoSource, MovieSpecifics,
-            PartialMetadataPerson, PartialMetadataWithoutId, PeopleSearchItem,
-            PersonSourceSpecifics, ShowEpisode, ShowSeason, ShowSpecifics, WatchProvider,
+            ExternalIdentifiers, MediaDetails, MetadataGroupSearchItem, MetadataImage,
+            MetadataImageForMediaDetails, MetadataPerson, MetadataSearchItem, MetadataVideo,
+            MetadataVideoSource, MovieSpecifics, PartialMetadataPerson, PartialMetadataWithoutId,
+            PeopleSearchItem, PersonSourceSpecifics, ShowEpisode, ShowSeason, ShowSpecifics,
+            WatchProvider,
         },
         IdObject, NamedObject, SearchDetails, SearchResults, StoredUrl,
     },
@@ -355,6 +356,20 @@ impl TmdbService {
             .map_err(|e| anyhow!(e))?;
         Ok(!changes.changes.is_empty())
     }
+
+    async fn get_external_identifiers(
+        &self,
+        type_: &str,
+        identifier: &str,
+    ) -> Result<ExternalIdentifiers> {
+        let rsp = self
+            .client
+            .get(format!("{}/{}/external_ids", type_, identifier))
+            .send()
+            .await
+            .map_err(|e| anyhow!(e))?;
+        rsp.json().await.map_err(|e| anyhow!(e))
+    }
 }
 
 impl MediaProviderLanguages for TmdbService {
@@ -770,6 +785,10 @@ impl MediaProvider for TmdbMovieService {
             .base
             .get_all_watch_providers("movie", identifier)
             .await?;
+        let external_identifiers = self
+            .base
+            .get_external_identifiers("movie", identifier)
+            .await?;
         Ok(MediaDetails {
             identifier: data.id.to_string(),
             is_nsfw: data.adult,
@@ -817,6 +836,7 @@ impl MediaProvider for TmdbMovieService {
                 .map(|c| c.id.to_string())
                 .collect(),
             watch_providers,
+            external_identifiers: Some(external_identifiers),
             ..Default::default()
         })
     }
@@ -1124,6 +1144,7 @@ impl MediaProvider for TmdbShowService {
             .flat_map(|s| s.episodes.iter())
             .count();
         let watch_providers = self.base.get_all_watch_providers("tv", identifier).await?;
+        let external_identifiers = self.base.get_external_identifiers("tv", identifier).await?;
         Ok(MediaDetails {
             identifier: show_data.id.to_string(),
             title: show_data.name.unwrap(),
@@ -1210,6 +1231,7 @@ impl MediaProvider for TmdbShowService {
             }),
             suggestions,
             watch_providers,
+            external_identifiers: Some(external_identifiers),
             provider_rating: if let Some(av) = show_data.vote_average {
                 if av != dec!(0) {
                     Some(av * dec!(10))
diff --git a/apps/backend/src/users.rs b/apps/backend/src/users.rs
index 66e8b47e02..1d7e31916f 100644
--- a/apps/backend/src/users.rs
+++ b/apps/backend/src/users.rs
@@ -290,7 +290,7 @@ pub struct UserGeneralPreferences {
     pub watch_providers: Vec<String>,
     pub review_scale: UserReviewScale,
     pub disable_watch_providers: bool,
-    pub disable_yank_integrations: bool,
+    pub disable_integrations: bool,
     pub disable_navigation_animation: bool,
     pub dashboard: Vec<UserGeneralDashboardElement>,
 }
@@ -318,7 +318,7 @@ impl Default for UserGeneralPreferences {
                 },
             ],
             persist_queries: true,
-            disable_yank_integrations: false,
+            disable_integrations: false,
             disable_navigation_animation: false,
             disable_videos: false,
             disable_watch_providers: false,
diff --git a/apps/frontend/app/routes/_dashboard.settings.integrations.tsx b/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
index 8bf3d25873..81dd33c04c 100644
--- a/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.integrations.tsx
@@ -10,6 +10,7 @@ import {
 	Flex,
 	Group,
 	Modal,
+	MultiSelect,
 	NumberInput,
 	Paper,
 	Select,
@@ -27,12 +28,12 @@ import {
 	CreateUserIntegrationDocument,
 	DeleteUserIntegrationDocument,
 	GenerateAuthTokenDocument,
-	IntegrationSource,
+	IntegrationProvider,
 	UpdateUserIntegrationDocument,
 	UserIntegrationsDocument,
 	type UserIntegrationsQuery,
 } from "@ryot/generated/graphql/backend/graphql";
-import { changeCase, processSubmission } from "@ryot/ts-utils";
+import { changeCase, isString, processSubmission } from "@ryot/ts-utils";
 import {
 	IconCheck,
 	IconCopy,
@@ -49,10 +50,15 @@ import { z } from "zod";
 import { zx } from "zodix";
 import { confirmWrapper } from "~/components/confirmation";
 import { dayjsLib } from "~/lib/generals";
-import { useConfirmSubmit } from "~/lib/hooks";
+import { useConfirmSubmit, useUserCollections } from "~/lib/hooks";
 import { createToastHeaders, serverGqlService } from "~/lib/utilities.server";
 
-const YANK_INTEGRATIONS = [IntegrationSource.Audiobookshelf];
+const YANK_INTEGRATIONS = [IntegrationProvider.Audiobookshelf];
+const PUSH_INTEGRATIONS = [
+	IntegrationProvider.Radarr,
+	IntegrationProvider.Sonarr,
+];
+const NO_SHOW_URL = [...YANK_INTEGRATIONS, ...PUSH_INTEGRATIONS];
 
 export const loader = unstable_defineLoader(async ({ request }) => {
 	const [{ userIntegrations }] = await Promise.all([
@@ -139,15 +145,30 @@ export const action = unstable_defineAction(async ({ request }) => {
 const MINIMUM_PROGRESS = "2";
 const MAXIMUM_PROGRESS = "95";
 
+const commaDelimitedString = z
+	.string()
+	.optional()
+	.transform((v) => (isString(v) ? v.split(",") : undefined));
+
 const createSchema = z.object({
-	source: z.nativeEnum(IntegrationSource),
-	minimumProgress: z.string().default(MINIMUM_PROGRESS),
-	maximumProgress: z.string().default(MAXIMUM_PROGRESS),
-	sourceSpecifics: z
+	provider: z.nativeEnum(IntegrationProvider),
+	minimumProgress: z.string().optional(),
+	maximumProgress: z.string().optional(),
+	providerSpecifics: z
 		.object({
 			plexUsername: z.string().optional(),
 			audiobookshelfBaseUrl: z.string().optional(),
 			audiobookshelfToken: z.string().optional(),
+			radarrBaseUrl: z.string().optional(),
+			radarrApiKey: z.string().optional(),
+			radarrProfileId: z.number().optional(),
+			radarrRootFolderPath: z.string().optional(),
+			radarrSyncCollectionIds: commaDelimitedString,
+			sonarrBaseUrl: z.string().optional(),
+			sonarrApiKey: z.string().optional(),
+			sonarrProfileId: z.number().optional(),
+			sonarrRootFolderPath: z.string().optional(),
+			sonarrSyncCollectionIds: commaDelimitedString,
 		})
 		.optional(),
 });
@@ -284,7 +305,7 @@ const DisplayIntegration = (props: {
 					<Box>
 						<Group gap={4}>
 							<Text size="sm" fw="bold">
-								{changeCase(props.integration.source)}
+								{changeCase(props.integration.provider)}
 							</Text>
 							{props.integration.isDisabled ? (
 								<Text size="xs">(Paused)</Text>
@@ -301,7 +322,7 @@ const DisplayIntegration = (props: {
 						) : null}
 					</Box>
 					<Group>
-						{!YANK_INTEGRATIONS.includes(props.integration.source) ? (
+						{!NO_SHOW_URL.includes(props.integration.provider) ? (
 							<ActionIcon color="blue" onClick={integrationInputToggle}>
 								{integrationInputOpened ? <IconEyeClosed /> : <IconEye />}
 							</ActionIcon>
@@ -357,7 +378,7 @@ const CreateIntegrationModal = (props: {
 	createModalOpened: boolean;
 	closeIntegrationModal: () => void;
 }) => {
-	const [source, setSource] = useState<IntegrationSource | null>(null);
+	const [provider, setProvider] = useState<IntegrationProvider | null>(null);
 
 	return (
 		<Modal
@@ -374,16 +395,16 @@ const CreateIntegrationModal = (props: {
 			>
 				<Stack>
 					<Select
-						label="Select a source"
-						name="source"
+						label="Select a provider"
+						name="provider"
 						required
-						data={Object.values(IntegrationSource).map((is) => ({
+						data={Object.values(IntegrationProvider).map((is) => ({
 							label: changeCase(is),
 							value: is,
 						}))}
-						onChange={(e) => setSource(e as IntegrationSource)}
+						onChange={(e) => setProvider(e as IntegrationProvider)}
 					/>
-					{source ? (
+					{provider && !PUSH_INTEGRATIONS.includes(provider) ? (
 						<Group wrap="nowrap">
 							<NumberInput
 								size="xs"
@@ -407,29 +428,31 @@ const CreateIntegrationModal = (props: {
 							/>
 						</Group>
 					) : null}
-					{match(source)
-						.with(IntegrationSource.Audiobookshelf, () => (
+					{match(provider)
+						.with(IntegrationProvider.Audiobookshelf, () => (
 							<>
 								<TextInput
 									label="Base Url"
 									required
-									name="sourceSpecifics.audiobookshelfBaseUrl"
+									name="providerSpecifics.audiobookshelfBaseUrl"
 								/>
 								<TextInput
 									label="Token"
 									required
-									name="sourceSpecifics.audiobookshelfToken"
+									name="providerSpecifics.audiobookshelfToken"
 								/>
 							</>
 						))
-						.with(IntegrationSource.Plex, () => (
+						.with(IntegrationProvider.Plex, () => (
 							<>
 								<TextInput
 									label="Username"
-									name="sourceSpecifics.plexUsername"
+									name="providerSpecifics.plexUsername"
 								/>
 							</>
 						))
+						.with(IntegrationProvider.Radarr, () => <ArrInputs name="radarr" />)
+						.with(IntegrationProvider.Sonarr, () => <ArrInputs name="sonarr" />)
 						.otherwise(() => undefined)}
 					<Button type="submit">Submit</Button>
 				</Stack>
@@ -438,6 +461,47 @@ const CreateIntegrationModal = (props: {
 	);
 };
 
+const ArrInputs = (props: { name: string }) => {
+	const collections = useUserCollections();
+
+	return (
+		<>
+			<TextInput
+				required
+				label="Base Url"
+				name={`providerSpecifics.${props.name}BaseUrl`}
+			/>
+			<TextInput
+				required
+				label="Token"
+				name={`providerSpecifics.${props.name}ApiKey`}
+			/>
+			<NumberInput
+				required
+				hideControls
+				defaultValue={1}
+				label="Profile ID"
+				name={`providerSpecifics.${props.name}ProfileId`}
+			/>
+			<TextInput
+				required
+				label="Root Folder"
+				name={`providerSpecifics.${props.name}RootFolderPath`}
+			/>
+			<MultiSelect
+				required
+				searchable
+				label="Collections"
+				name={`providerSpecifics.${props.name}SyncCollectionIds`}
+				data={collections.map((c) => ({
+					label: c.name,
+					value: c.id,
+				}))}
+			/>
+		</>
+	);
+};
+
 const UpdateIntegrationModal = (props: {
 	updateIntegrationData: Integration | null;
 	closeIntegrationModal: () => void;
@@ -449,44 +513,54 @@ const UpdateIntegrationModal = (props: {
 			centered
 			withCloseButton={false}
 		>
-			<Form
-				replace
-				method="POST"
-				onSubmit={() => props.closeIntegrationModal()}
-				action={withQuery("", { intent: "update" })}
-			>
-				<input
-					type="hidden"
-					name="integrationId"
-					defaultValue={props.updateIntegrationData?.id}
-				/>
-				<Stack>
-					<Group wrap="nowrap">
-						<NumberInput
-							size="xs"
-							label="Minimum progress"
-							description="Progress will not be synced below this value"
-							name="minimumProgress"
-							defaultValue={props.updateIntegrationData?.minimumProgress}
-						/>
-						<NumberInput
-							size="xs"
-							label="Maximum progress"
-							description="After this value, progress will be marked as completed"
-							name="maximumProgress"
-							defaultValue={props.updateIntegrationData?.maximumProgress}
-						/>
-					</Group>
-					<Checkbox
-						name="isDisabled"
-						label="Pause integration"
-						defaultChecked={
-							props.updateIntegrationData?.isDisabled || undefined
-						}
+			{props.updateIntegrationData ? (
+				<Form
+					replace
+					method="POST"
+					onSubmit={() => props.closeIntegrationModal()}
+					action={withQuery("", { intent: "update" })}
+				>
+					<input
+						type="hidden"
+						name="integrationId"
+						defaultValue={props.updateIntegrationData.id}
 					/>
-					<Button type="submit">Submit</Button>
-				</Stack>
-			</Form>
+					<Stack>
+						{!PUSH_INTEGRATIONS.includes(
+							props.updateIntegrationData.provider,
+						) ? (
+							<Group wrap="nowrap">
+								<NumberInput
+									size="xs"
+									label="Minimum progress"
+									description="Progress will not be synced below this value"
+									name="minimumProgress"
+									defaultValue={
+										props.updateIntegrationData.minimumProgress || undefined
+									}
+								/>
+								<NumberInput
+									size="xs"
+									label="Maximum progress"
+									description="After this value, progress will be marked as completed"
+									name="maximumProgress"
+									defaultValue={
+										props.updateIntegrationData.maximumProgress || undefined
+									}
+								/>
+							</Group>
+						) : null}
+						<Checkbox
+							name="isDisabled"
+							label="Pause integration"
+							defaultChecked={
+								props.updateIntegrationData.isDisabled || undefined
+							}
+						/>
+						<Button type="submit">Submit</Button>
+					</Stack>
+				</Form>
+			) : null}
 		</Modal>
 	);
 };
diff --git a/apps/frontend/app/routes/_dashboard.settings.miscellaneous.tsx b/apps/frontend/app/routes/_dashboard.settings.miscellaneous.tsx
index 057458f739..4c755c42d9 100644
--- a/apps/frontend/app/routes/_dashboard.settings.miscellaneous.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.miscellaneous.tsx
@@ -153,12 +153,12 @@ export default function Page() {
 							<Box>
 								<Title order={4}>Synchronize integrations progress</Title>
 								<Text>
-									Get data from all configured integrations and update progress
-									if applicable. The more integrations you have enabled, the
-									longer this will take.
+									Get/push data for all configured integrations and update
+									progress if applicable. The more integrations you have
+									enabled, the longer this will take.
 								</Text>
 							</Box>
-							<Button {...btnProps} value={BackgroundJob.YankIntegrationsData}>
+							<Button {...btnProps} value={BackgroundJob.SyncIntegrationsData}>
 								Synchronize
 							</Button>
 						</Stack>
diff --git a/apps/frontend/app/routes/_dashboard.settings.preferences.tsx b/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
index 85a4fdd1be..473266fb2f 100644
--- a/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
+++ b/apps/frontend/app/routes/_dashboard.settings.preferences.tsx
@@ -303,7 +303,7 @@ export default function Page() {
 								{(
 									[
 										"displayNsfw",
-										"disableYankIntegrations",
+										"disableIntegrations",
 										"disableNavigationAnimation",
 										"disableVideos",
 										"disableReviews",
@@ -320,8 +320,8 @@ export default function Page() {
 												() => "Whether NSFW will be displayed",
 											)
 											.with(
-												"disableYankIntegrations",
-												() => "Disable yank integrations",
+												"disableIntegrations",
+												() => "Disable all integrations",
 											)
 											.with(
 												"disableNavigationAnimation",
diff --git a/docs/content/integrations.md b/docs/content/integrations.md
index 04df0cf932..27d80fe7c9 100644
--- a/docs/content/integrations.md
+++ b/docs/content/integrations.md
@@ -5,6 +5,7 @@ types:
 
 - _Yank_: Progress data is downloaded from an externally running server at a periodic
   interval.
+- _Push_: Ryot sends data to an external service.
 - _Sink_: An external client publishes progress updates to the Ryot server.
 
 ## Yank integrations
@@ -14,7 +15,7 @@ to your profile. To do so, go to the "Settings" tab and add a new integration un
 "Integrations" tab.
 
 You can configure the interval at which the data is fetched from the external using the
-`integration.pull_every_minutes` configuration key. Defaults to `5` (minutes).
+`integration.sync_every_minutes` configuration key. Defaults to `5` (minutes).
 
 ### Audiobookshelf
 
@@ -31,6 +32,24 @@ have an Audible ID or ITunes ID or ISBN.
 2. Go to your Ryot user settings and add the correct details as described in the
    [yank](#yank-integrations) section.
 
+## Push integrations
+
+Follow the same instructions as the [yank](#yank-integrations) integrations to add.
+
+### Radarr
+
+Automatically add movies in the selected collections to Radarr.
+
+1. Obtain your Radarr API key by going to the Radarr general settings page.
+2. Fill the inputs in the integration settings page with the correct details.
+
+### Sonarr
+
+Automatically add shows in the selected collections to Sonarr.
+
+1. Obtain your Sonarr API key by going to the Sonarr general settings page.
+2. Fill the inputs in the integration settings page with the correct details.
+
 ## Sink integrations
 
 All webhook URLs follow this format:
diff --git a/docs/includes/backend-config-schema.yaml b/docs/includes/backend-config-schema.yaml
index 2b6201ba25..d8ce4a928a 100644
--- a/docs/includes/backend-config-schema.yaml
+++ b/docs/includes/backend-config-schema.yaml
@@ -112,10 +112,9 @@ frontend:
 
 # Settings related to external integrations.
 integration:
-  # Sync data from [yank](/docs/guides/integrations.md) based integrations
-  # every `n` minutes.
-  # @envvar INTEGRATION_PULL_EVERY_MINUTES
-  pull_every_minutes: 5
+  # Sync data from push and yank based integrations every `n` minutes.
+  # @envvar INTEGRATION_SYNC_EVERY_MINUTES
+  sync_every_minutes: 5
 
 # Settings related to media.
 media:
diff --git a/libs/config/src/lib.rs b/libs/config/src/lib.rs
index 56fa846c72..390e95f898 100644
--- a/libs/config/src/lib.rs
+++ b/libs/config/src/lib.rs
@@ -320,10 +320,9 @@ pub struct FrontendConfig {
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
 #[config(rename_all = "snake_case", env_prefix = "INTEGRATION_")]
 pub struct IntegrationConfig {
-    /// Sync data from [yank](/docs/guides/integrations.md) based integrations
-    /// every `n` minutes.
+    /// Sync data from push and yank based integrations every `n` minutes.
     #[setting(default = 5)]
-    pub pull_every_minutes: i32,
+    pub sync_every_minutes: i32,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, Config)]
diff --git a/libs/database/src/definitions.rs b/libs/database/src/definitions.rs
index d04e7094a9..d05327c9b9 100644
--- a/libs/database/src/definitions.rs
+++ b/libs/database/src/definitions.rs
@@ -390,7 +390,7 @@ pub enum MetadataToMetadataRelation {
 pub enum UserToMediaReason {
     // There is at-least one element in the seen history
     Seen,
-    // User has watched this media completely (most applies to shows, podcasts etc.)
+    // User has watched this media completely (mostly applies to shows, podcasts etc.)
     Finished,
     Reviewed,
     Collection,
@@ -423,6 +423,7 @@ pub enum UserToMediaReason {
 pub enum IntegrationLot {
     Yank,
     Sink,
+    Push,
 }
 
 #[derive(
@@ -445,12 +446,14 @@ pub enum IntegrationLot {
     rename_all = "snake_case"
 )]
 #[serde(rename_all = "snake_case")]
-pub enum IntegrationSource {
+pub enum IntegrationProvider {
     Audiobookshelf,
     Jellyfin,
     Emby,
     Plex,
     Kodi,
+    Radarr,
+    Sonarr,
 }
 
 #[derive(
diff --git a/libs/database/src/migrations/m20230410_create_metadata.rs b/libs/database/src/migrations/m20230410_create_metadata.rs
index 47fb297843..90f55a9406 100644
--- a/libs/database/src/migrations/m20230410_create_metadata.rs
+++ b/libs/database/src/migrations/m20230410_create_metadata.rs
@@ -53,6 +53,7 @@ pub enum Metadata {
     VisualNovelSpecifics,
     WatchProviders,
     StateChanges,
+    ExternalIdentifiers,
 }
 
 #[async_trait::async_trait]
@@ -101,6 +102,7 @@ impl MigrationTrait for Migration {
                     .col(ColumnDef::new(Metadata::VisualNovelSpecifics).json_binary())
                     .col(ColumnDef::new(Metadata::WatchProviders).json_binary())
                     .col(ColumnDef::new(Metadata::StateChanges).json_binary())
+                    .col(ColumnDef::new(Metadata::ExternalIdentifiers).json_binary())
                     .to_owned(),
             )
             .await?;
diff --git a/libs/database/src/migrations/m20231016_create_collection_to_entity.rs b/libs/database/src/migrations/m20231016_create_collection_to_entity.rs
index 495d3adf83..15b552835c 100644
--- a/libs/database/src/migrations/m20231016_create_collection_to_entity.rs
+++ b/libs/database/src/migrations/m20231016_create_collection_to_entity.rs
@@ -59,6 +59,7 @@ pub enum CollectionToEntity {
     CreatedOn,
     LastUpdatedOn,
     Information,
+    SystemInformation,
     EntityId,
     EntityLot,
     // the entities that can be added to a collection
@@ -119,6 +120,12 @@ impl MigrationTrait for Migration {
                             .not_null()
                             .extra(ENTITY_LOT_SQL),
                     )
+                    .col(
+                        ColumnDef::new(CollectionToEntity::SystemInformation)
+                            .json_binary()
+                            .not_null()
+                            .default("{}"),
+                    )
                     .foreign_key(
                         ForeignKey::create()
                             .name("collection_to_entity-fk1")
diff --git a/libs/database/src/migrations/m20240607_create_integration.rs b/libs/database/src/migrations/m20240607_create_integration.rs
index 368026d914..688a94b0fd 100644
--- a/libs/database/src/migrations/m20240607_create_integration.rs
+++ b/libs/database/src/migrations/m20240607_create_integration.rs
@@ -10,10 +10,10 @@ pub enum Integration {
     Table,
     Id,
     Lot,
-    Source,
+    Provider,
     CreatedOn,
     LastTriggeredOn,
-    SourceSpecifics,
+    ProviderSpecifics,
     UserId,
     MinimumProgress,
     MaximumProgress,
@@ -34,7 +34,7 @@ impl MigrationTrait for Migration {
                             .primary_key(),
                     )
                     .col(ColumnDef::new(Integration::Lot).text().not_null())
-                    .col(ColumnDef::new(Integration::Source).text().not_null())
+                    .col(ColumnDef::new(Integration::Provider).text().not_null())
                     .col(
                         ColumnDef::new(Integration::CreatedOn)
                             .timestamp_with_time_zone()
@@ -42,18 +42,10 @@ impl MigrationTrait for Migration {
                             .default(Expr::current_timestamp()),
                     )
                     .col(ColumnDef::new(Integration::LastTriggeredOn).timestamp_with_time_zone())
-                    .col(ColumnDef::new(Integration::SourceSpecifics).json_binary())
+                    .col(ColumnDef::new(Integration::ProviderSpecifics).json_binary())
                     .col(ColumnDef::new(Integration::UserId).text().not_null())
-                    .col(
-                        ColumnDef::new(Integration::MinimumProgress)
-                            .decimal()
-                            .not_null(),
-                    )
-                    .col(
-                        ColumnDef::new(Integration::MaximumProgress)
-                            .decimal()
-                            .not_null(),
-                    )
+                    .col(ColumnDef::new(Integration::MinimumProgress).decimal())
+                    .col(ColumnDef::new(Integration::MaximumProgress).decimal())
                     .col(ColumnDef::new(Integration::IsDisabled).boolean())
                     .foreign_key(
                         ForeignKey::create()
diff --git a/libs/database/src/migrations/m20240730_changes_for_push_integrations.rs b/libs/database/src/migrations/m20240730_changes_for_push_integrations.rs
new file mode 100644
index 0000000000..79498b3d55
--- /dev/null
+++ b/libs/database/src/migrations/m20240730_changes_for_push_integrations.rs
@@ -0,0 +1,63 @@
+use sea_orm_migration::prelude::*;
+
+#[derive(DeriveMigrationName)]
+pub struct Migration;
+
+#[async_trait::async_trait]
+impl MigrationTrait for Migration {
+    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
+        let db = manager.get_connection();
+        db.execute_unprepared(
+            r#"
+UPDATE "user" SET preferences = JSONB_SET(preferences, '{general,disable_integrations}',
+preferences->'general'->'disable_yank_integrations', true);
+            "#,
+        )
+        .await?;
+        db.execute_unprepared(
+            r#"
+ALTER TABLE "integration" ALTER COLUMN "minimum_progress" DROP NOT NULL;
+ALTER TABLE "integration" ALTER COLUMN "maximum_progress" DROP NOT NULL;
+            "#,
+        )
+        .await?;
+        if manager.has_column("integration", "source").await? {
+            db.execute_unprepared(
+                r#"ALTER TABLE "integration" RENAME COLUMN "source" TO "provider""#,
+            )
+            .await?;
+        }
+        if manager
+            .has_column("integration", "source_specifics")
+            .await?
+        {
+            db.execute_unprepared(
+                r#"ALTER TABLE "integration" RENAME COLUMN "source_specifics" TO "provider_specifics""#,
+            )
+            .await?;
+        }
+        db.execute_unprepared(
+            r#"
+ALTER TABLE "metadata" ADD COLUMN IF NOT EXISTS "external_identifiers" jsonb;
+            "#,
+        )
+        .await?;
+        db.execute_unprepared(
+            r#"
+ALTER TABLE "collection_to_entity" ADD COLUMN IF NOT EXISTS "system_information" jsonb not null default '{}';
+            "#,
+        )
+        .await?;
+        db.execute_unprepared(
+            r#"
+UPDATE "user_to_entity" SET "needs_to_be_updated" = TRUE WHERE 'finished' = ANY("media_reason");
+            "#,
+        )
+        .await?;
+        Ok(())
+    }
+
+    async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
+        Ok(())
+    }
+}
diff --git a/libs/database/src/migrations/mod.rs b/libs/database/src/migrations/mod.rs
index 3e0ce40f3c..0f3d084544 100644
--- a/libs/database/src/migrations/mod.rs
+++ b/libs/database/src/migrations/mod.rs
@@ -42,6 +42,7 @@ mod m20240722_remove_columns_from_user_table;
 mod m20240723_remove_integration_columns_from_user_table;
 mod m20240724_add_new_columns_to_collection_to_entity;
 mod m20240724_zzz_new_generated_collection_to_entity_columns;
+mod m20240730_changes_for_push_integrations;
 
 pub use m20230410_create_metadata::Metadata as AliasedMetadata;
 pub use m20230413_create_person::Person as AliasedPerson;
@@ -105,6 +106,7 @@ impl MigratorTrait for Migrator {
             Box::new(m20240723_remove_integration_columns_from_user_table::Migration),
             Box::new(m20240724_add_new_columns_to_collection_to_entity::Migration),
             Box::new(m20240724_zzz_new_generated_collection_to_entity_columns::Migration),
+            Box::new(m20240730_changes_for_push_integrations::Migration),
         ]
     }
 }
diff --git a/libs/generated/src/graphql/backend/gql.ts b/libs/generated/src/graphql/backend/gql.ts
index cd0628c66b..f88df859d9 100644
--- a/libs/generated/src/graphql/backend/gql.ts
+++ b/libs/generated/src/graphql/backend/gql.ts
@@ -36,10 +36,10 @@ const documents = {
     "query UserMetadataDetails($metadataId: String!) {\n  userMetadataDetails(metadataId: $metadataId) {\n    mediaReason\n    hasInteracted\n    collections {\n      ...CollectionPart\n    }\n    inProgress {\n      ...SeenPart\n    }\n    history {\n      ...SeenPart\n    }\n    averageRating\n    unitsConsumed\n    reviews {\n      ...ReviewItemPart\n    }\n    seenByAllCount\n    seenByUserCount\n    nextEntry {\n      season\n      volume\n      episode\n      chapter\n    }\n    showProgress {\n      timesSeen\n      seasonNumber\n      episodes {\n        episodeNumber\n        timesSeen\n      }\n    }\n    podcastProgress {\n      episodeNumber\n      timesSeen\n    }\n  }\n}": types.UserMetadataDetailsDocument,
     "query UserMetadataGroupDetails($metadataGroupId: String!) {\n  userMetadataGroupDetails(metadataGroupId: $metadataGroupId) {\n    reviews {\n      ...ReviewItemPart\n    }\n    collections {\n      ...CollectionPart\n    }\n  }\n}": types.UserMetadataGroupDetailsDocument,
     "query UserPersonDetails($personId: String!) {\n  userPersonDetails(personId: $personId) {\n    collections {\n      ...CollectionPart\n    }\n    reviews {\n      ...ReviewItemPart\n    }\n  }\n}": types.UserPersonDetailsDocument,
-    "query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableWatchProviders\n      disableYankIntegrations\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}": types.UserPreferencesDocument,
+    "query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableIntegrations\n      disableWatchProviders\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}": types.UserPreferencesDocument,
     "query UserWorkoutsList($input: SearchInput!) {\n  userWorkoutsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items {\n      id\n      name\n      startTime\n      endTime\n      summary {\n        ...WorkoutSummaryPart\n      }\n    }\n  }\n}": types.UserWorkoutsListDocument,
     "query WorkoutDetails($workoutId: String!) {\n  workoutDetails(workoutId: $workoutId) {\n    collections {\n      ...CollectionPart\n    }\n    details {\n      id\n      name\n      endTime\n      startTime\n      repeatedFrom\n      summary {\n        ...WorkoutSummaryPart\n      }\n      information {\n        ...WorkoutInformationPart\n      }\n    }\n  }\n}": types.WorkoutDetailsDocument,
-    "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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}": types.GetOidcRedirectUrlDocument,
+    "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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    provider\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}": 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  chapter\n  volume\n}\n\nfragment CalendarEventPart on GraphqlCalendarEvent {\n  date\n  metadataId\n  metadataLot\n  episodeName\n  metadataTitle\n  metadataImage\n  calendarEventId\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\n  }\n}\n\nfragment SeenPart on Seen {\n  id\n  progress\n  providerWatchedOn\n  state\n  startedOn\n  finishedOn\n  lastUpdatedOn\n  numTimesUpdated\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  identifier\n  title\n  image\n  publishYear\n}\n\nfragment WorkoutOrExerciseTotalsPart on WorkoutOrExerciseTotals {\n  personalBestsAchieved\n  weight\n  reps\n  distance\n  duration\n  restTime\n}\n\nfragment EntityAssetsPart on EntityAssets {\n  images\n  videos\n}\n\nfragment WorkoutSetStatisticPart on WorkoutSetStatistic {\n  duration\n  distance\n  reps\n  weight\n  oneRm\n  pace\n  volume\n}\n\nfragment WorkoutSummaryPart on WorkoutSummary {\n  total {\n    ...WorkoutOrExerciseTotalsPart\n  }\n  exercises {\n    numSets\n    id\n    lot\n    bestSet {\n      statistic {\n        ...WorkoutSetStatisticPart\n      }\n      lot\n      personalBests\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  textOriginal\n  textRendered\n  isSpoiler\n  visibility\n  postedOn\n  postedBy {\n    id\n    name\n  }\n  comments {\n    id\n    text\n    createdOn\n    user {\n      id\n      name\n    }\n    likedBy\n  }\n  showExtraInformation {\n    ...SeenShowExtraInformationPart\n  }\n  podcastExtraInformation {\n    ...SeenPodcastExtraInformationPart\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  exercises {\n    name\n    lot\n    notes\n    restTime\n    total {\n      ...WorkoutOrExerciseTotalsPart\n    }\n    supersetWith\n    assets {\n      ...EntityAssetsPart\n    }\n    sets {\n      statistic {\n        ...WorkoutSetStatisticPart\n      }\n      note\n      lot\n      personalBests\n      confirmedAt\n    }\n  }\n}": types.SeenPodcastExtraInformationPartFragmentDoc,
 };
 
@@ -152,7 +152,7 @@ export function graphql(source: "query UserPersonDetails($personId: String!) {\n
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
-export function graphql(source: "query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableWatchProviders\n      disableYankIntegrations\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}"): (typeof documents)["query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableWatchProviders\n      disableYankIntegrations\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}"];
+export function graphql(source: "query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableIntegrations\n      disableWatchProviders\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}"): (typeof documents)["query UserPreferences {\n  userPreferences {\n    general {\n      reviewScale\n      displayNsfw\n      disableVideos\n      persistQueries\n      watchProviders\n      disableReviews\n      disableIntegrations\n      disableWatchProviders\n      disableNavigationAnimation\n      dashboard {\n        section\n        hidden\n        numElements\n      }\n    }\n    fitness {\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      exercises {\n        saveHistory\n        unitSystem\n      }\n    }\n    notifications {\n      toSend\n      enabled\n    }\n    featuresEnabled {\n      others {\n        calendar\n        collections\n      }\n      fitness {\n        enabled\n        workouts\n        measurements\n      }\n      media {\n        enabled\n        anime\n        audioBook\n        book\n        manga\n        movie\n        podcast\n        show\n        videoGame\n        visualNovel\n        people\n        groups\n        genres\n      }\n    }\n  }\n}"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
@@ -164,7 +164,7 @@ export function graphql(source: "query WorkoutDetails($workoutId: String!) {\n
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
-export function graphql(source: "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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"): (typeof documents)["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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    source\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"];
+export function graphql(source: "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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    provider\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"): (typeof documents)["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 ProvidersLanguageInformation {\n  providersLanguageInformation {\n    supported\n    default\n    source\n  }\n}\n\nquery UserExports {\n  userExports {\n    startedAt\n    endedAt\n    url\n    exported\n  }\n}\n\nquery UserCollectionsList($name: String) {\n  userCollectionsList(name: $name) {\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\nquery UserIntegrations {\n  userIntegrations {\n    id\n    lot\n    provider\n    createdOn\n    isDisabled\n    maximumProgress\n    minimumProgress\n    lastTriggeredOn\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 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 MetadataGroupsList($input: SearchInput!) {\n  metadataGroupsList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}\n\nquery PeopleList($input: PeopleListInput!) {\n  peopleList(input: $input) {\n    details {\n      total\n      nextPage\n    }\n    items\n  }\n}"];
 /**
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
  */
diff --git a/libs/generated/src/graphql/backend/graphql.ts b/libs/generated/src/graphql/backend/graphql.ts
index 4ef237c8df..729dee4c26 100644
--- a/libs/generated/src/graphql/backend/graphql.ts
+++ b/libs/generated/src/graphql/backend/graphql.ts
@@ -81,9 +81,9 @@ export enum BackgroundJob {
   EvaluateWorkouts = 'EVALUATE_WORKOUTS',
   PerformBackgroundTasks = 'PERFORM_BACKGROUND_TASKS',
   RecalculateCalendarEvents = 'RECALCULATE_CALENDAR_EVENTS',
+  SyncIntegrationsData = 'SYNC_INTEGRATIONS_DATA',
   UpdateAllExercises = 'UPDATE_ALL_EXERCISES',
-  UpdateAllMetadata = 'UPDATE_ALL_METADATA',
-  YankIntegrationsData = 'YANK_INTEGRATIONS_DATA'
+  UpdateAllMetadata = 'UPDATE_ALL_METADATA'
 }
 
 export type BookSpecifics = {
@@ -246,10 +246,10 @@ export type CreateReviewCommentInput = {
 };
 
 export type CreateUserIntegrationInput = {
-  maximumProgress: Scalars['Decimal']['input'];
-  minimumProgress: Scalars['Decimal']['input'];
-  source: IntegrationSource;
-  sourceSpecifics?: InputMaybe<IntegrationSourceSpecificsInput>;
+  maximumProgress?: InputMaybe<Scalars['Decimal']['input']>;
+  minimumProgress?: InputMaybe<Scalars['Decimal']['input']>;
+  provider: IntegrationProvider;
+  providerSpecifics?: InputMaybe<IntegrationSourceSpecificsInput>;
 };
 
 export type CreateUserNotificationPlatformInput = {
@@ -700,35 +700,41 @@ export type Integration = {
   isDisabled?: Maybe<Scalars['Boolean']['output']>;
   lastTriggeredOn?: Maybe<Scalars['DateTime']['output']>;
   lot: IntegrationLot;
-  maximumProgress: Scalars['Decimal']['output'];
-  minimumProgress: Scalars['Decimal']['output'];
-  source: IntegrationSource;
-  sourceSpecifics?: Maybe<IntegrationSourceSpecifics>;
+  maximumProgress?: Maybe<Scalars['Decimal']['output']>;
+  minimumProgress?: Maybe<Scalars['Decimal']['output']>;
+  provider: IntegrationProvider;
 };
 
 export enum IntegrationLot {
+  Push = 'PUSH',
   Sink = 'SINK',
   Yank = 'YANK'
 }
 
-export enum IntegrationSource {
+export enum IntegrationProvider {
   Audiobookshelf = 'AUDIOBOOKSHELF',
   Emby = 'EMBY',
   Jellyfin = 'JELLYFIN',
   Kodi = 'KODI',
-  Plex = 'PLEX'
+  Plex = 'PLEX',
+  Radarr = 'RADARR',
+  Sonarr = 'SONARR'
 }
 
-export type IntegrationSourceSpecifics = {
-  audiobookshelfBaseUrl?: Maybe<Scalars['String']['output']>;
-  audiobookshelfToken?: Maybe<Scalars['String']['output']>;
-  plexUsername?: Maybe<Scalars['String']['output']>;
-};
-
 export type IntegrationSourceSpecificsInput = {
   audiobookshelfBaseUrl?: InputMaybe<Scalars['String']['input']>;
   audiobookshelfToken?: InputMaybe<Scalars['String']['input']>;
   plexUsername?: InputMaybe<Scalars['String']['input']>;
+  radarrApiKey?: InputMaybe<Scalars['String']['input']>;
+  radarrBaseUrl?: InputMaybe<Scalars['String']['input']>;
+  radarrProfileId?: InputMaybe<Scalars['Int']['input']>;
+  radarrRootFolderPath?: InputMaybe<Scalars['String']['input']>;
+  radarrSyncCollectionIds?: InputMaybe<Array<Scalars['String']['input']>>;
+  sonarrApiKey?: InputMaybe<Scalars['String']['input']>;
+  sonarrBaseUrl?: InputMaybe<Scalars['String']['input']>;
+  sonarrProfileId?: InputMaybe<Scalars['Int']['input']>;
+  sonarrRootFolderPath?: InputMaybe<Scalars['String']['input']>;
+  sonarrSyncCollectionIds?: InputMaybe<Array<Scalars['String']['input']>>;
 };
 
 export type LoginError = {
@@ -2012,11 +2018,11 @@ export type UserGeneralDashboardElement = {
 
 export type UserGeneralPreferences = {
   dashboard: Array<UserGeneralDashboardElement>;
+  disableIntegrations: Scalars['Boolean']['output'];
   disableNavigationAnimation: Scalars['Boolean']['output'];
   disableReviews: Scalars['Boolean']['output'];
   disableVideos: Scalars['Boolean']['output'];
   disableWatchProviders: Scalars['Boolean']['output'];
-  disableYankIntegrations: Scalars['Boolean']['output'];
   displayNsfw: Scalars['Boolean']['output'];
   persistQueries: Scalars['Boolean']['output'];
   reviewScale: UserReviewScale;
@@ -2893,7 +2899,7 @@ export type UserPersonDetailsQuery = { userPersonDetails: { collections: Array<{
 export type UserPreferencesQueryVariables = Exact<{ [key: string]: never; }>;
 
 
-export type UserPreferencesQuery = { userPreferences: { general: { reviewScale: UserReviewScale, displayNsfw: boolean, disableVideos: boolean, persistQueries: boolean, watchProviders: Array<string>, disableReviews: boolean, disableWatchProviders: boolean, disableYankIntegrations: boolean, disableNavigationAnimation: boolean, dashboard: Array<{ section: DashboardElementLot, hidden: boolean, numElements?: number | null }> }, fitness: { measurements: { custom: Array<{ name: string, dataType: UserCustomMeasurementDataType }>, inbuilt: { weight: boolean, bodyMassIndex: boolean, totalBodyWater: boolean, muscle: boolean, leanBodyMass: boolean, bodyFat: boolean, boneMass: boolean, visceralFat: boolean, waistCircumference: boolean, waistToHeightRatio: boolean, hipCircumference: boolean, waistToHipRatio: boolean, chestCircumference: boolean, thighCircumference: boolean, bicepsCircumference: boolean, neckCircumference: boolean, bodyFatCaliper: boolean, chestSkinfold: boolean, abdominalSkinfold: boolean, thighSkinfold: boolean, basalMetabolicRate: boolean, totalDailyEnergyExpenditure: boolean, calories: boolean } }, exercises: { saveHistory: number, unitSystem: UserUnitSystem } }, notifications: { toSend: Array<MediaStateChanged>, enabled: boolean }, featuresEnabled: { others: { calendar: boolean, collections: boolean }, fitness: { enabled: boolean, workouts: boolean, measurements: boolean }, media: { enabled: boolean, anime: boolean, audioBook: boolean, book: boolean, manga: boolean, movie: boolean, podcast: boolean, show: boolean, videoGame: boolean, visualNovel: boolean, people: boolean, groups: boolean, genres: boolean } } } };
+export type UserPreferencesQuery = { userPreferences: { general: { reviewScale: UserReviewScale, displayNsfw: boolean, disableVideos: boolean, persistQueries: boolean, watchProviders: Array<string>, disableReviews: boolean, disableIntegrations: boolean, disableWatchProviders: boolean, disableNavigationAnimation: boolean, dashboard: Array<{ section: DashboardElementLot, hidden: boolean, numElements?: number | null }> }, fitness: { measurements: { custom: Array<{ name: string, dataType: UserCustomMeasurementDataType }>, inbuilt: { weight: boolean, bodyMassIndex: boolean, totalBodyWater: boolean, muscle: boolean, leanBodyMass: boolean, bodyFat: boolean, boneMass: boolean, visceralFat: boolean, waistCircumference: boolean, waistToHeightRatio: boolean, hipCircumference: boolean, waistToHipRatio: boolean, chestCircumference: boolean, thighCircumference: boolean, bicepsCircumference: boolean, neckCircumference: boolean, bodyFatCaliper: boolean, chestSkinfold: boolean, abdominalSkinfold: boolean, thighSkinfold: boolean, basalMetabolicRate: boolean, totalDailyEnergyExpenditure: boolean, calories: boolean } }, exercises: { saveHistory: number, unitSystem: UserUnitSystem } }, notifications: { toSend: Array<MediaStateChanged>, enabled: boolean }, featuresEnabled: { others: { calendar: boolean, collections: boolean }, fitness: { enabled: boolean, workouts: boolean, measurements: boolean }, media: { enabled: boolean, anime: boolean, audioBook: boolean, book: boolean, manga: boolean, movie: boolean, podcast: boolean, show: boolean, videoGame: boolean, visualNovel: boolean, people: boolean, groups: boolean, genres: boolean } } } };
 
 export type UserWorkoutsListQueryVariables = Exact<{
   input: SearchInput;
@@ -2955,7 +2961,7 @@ export type UserCollectionsListQuery = { userCollectionsList: Array<{ id: string
 export type UserIntegrationsQueryVariables = Exact<{ [key: string]: never; }>;
 
 
-export type UserIntegrationsQuery = { userIntegrations: Array<{ id: string, lot: IntegrationLot, source: IntegrationSource, createdOn: string, isDisabled?: boolean | null, maximumProgress: string, minimumProgress: string, lastTriggeredOn?: string | null }> };
+export type UserIntegrationsQuery = { userIntegrations: Array<{ id: string, lot: IntegrationLot, provider: IntegrationProvider, createdOn: string, isDisabled?: boolean | null, maximumProgress?: string | null, minimumProgress?: string | null, lastTriggeredOn?: string | null }> };
 
 export type UserNotificationPlatformsQueryVariables = Exact<{ [key: string]: never; }>;
 
@@ -3110,7 +3116,7 @@ export const UserMeasurementsListDocument = {"kind":"Document","definitions":[{"
 export const UserMetadataDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserMetadataDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userMetadataDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"metadataId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"metadataId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"mediaReason"}},{"kind":"Field","name":{"kind":"Name","value":"hasInteracted"}},{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"averageRating"}},{"kind":"Field","name":{"kind":"Name","value":"unitsConsumed"}},{"kind":"Field","name":{"kind":"Name","value":"reviews"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ReviewItemPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"seenByAllCount"}},{"kind":"Field","name":{"kind":"Name","value":"seenByUserCount"}},{"kind":"Field","name":{"kind":"Name","value":"nextEntry"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}},{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"chapter"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}},{"kind":"Field","name":{"kind":"Name","value":"seasonNumber"}},{"kind":"Field","name":{"kind":"Name","value":"episodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episodeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastProgress"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episodeNumber"}},{"kind":"Field","name":{"kind":"Name","value":"timesSeen"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Seen"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"progress"}},{"kind":"Field","name":{"kind":"Name","value":"providerWatchedOn"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"startedOn"}},{"kind":"Field","name":{"kind":"Name","value":"finishedOn"}},{"kind":"Field","name":{"kind":"Name","value":"lastUpdatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"numTimesUpdated"}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserMetadataDetailsQuery, UserMetadataDetailsQueryVariables>;
 export const UserMetadataGroupDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserMetadataGroupDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"metadataGroupId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userMetadataGroupDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"metadataGroupId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"metadataGroupId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviews"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ReviewItemPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}}]} as unknown as DocumentNode<UserMetadataGroupDetailsQuery, UserMetadataGroupDetailsQueryVariables>;
 export const UserPersonDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserPersonDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"personId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userPersonDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"personId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"personId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"reviews"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ReviewItemPart"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenAnimeExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenMangaExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chapter"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ReviewItemPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ReviewItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"rating"}},{"kind":"Field","name":{"kind":"Name","value":"textOriginal"}},{"kind":"Field","name":{"kind":"Name","value":"textRendered"}},{"kind":"Field","name":{"kind":"Name","value":"isSpoiler"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"postedOn"}},{"kind":"Field","name":{"kind":"Name","value":"postedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"text"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"likedBy"}}]}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"animeExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenAnimeExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"mangaExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenMangaExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserPersonDetailsQuery, UserPersonDetailsQueryVariables>;
-export const UserPreferencesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserPreferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userPreferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"general"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviewScale"}},{"kind":"Field","name":{"kind":"Name","value":"displayNsfw"}},{"kind":"Field","name":{"kind":"Name","value":"disableVideos"}},{"kind":"Field","name":{"kind":"Name","value":"persistQueries"}},{"kind":"Field","name":{"kind":"Name","value":"watchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableReviews"}},{"kind":"Field","name":{"kind":"Name","value":"disableWatchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableYankIntegrations"}},{"kind":"Field","name":{"kind":"Name","value":"disableNavigationAnimation"}},{"kind":"Field","name":{"kind":"Name","value":"dashboard"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"section"}},{"kind":"Field","name":{"kind":"Name","value":"hidden"}},{"kind":"Field","name":{"kind":"Name","value":"numElements"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"measurements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"custom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"dataType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inbuilt"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"bodyMassIndex"}},{"kind":"Field","name":{"kind":"Name","value":"totalBodyWater"}},{"kind":"Field","name":{"kind":"Name","value":"muscle"}},{"kind":"Field","name":{"kind":"Name","value":"leanBodyMass"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFat"}},{"kind":"Field","name":{"kind":"Name","value":"boneMass"}},{"kind":"Field","name":{"kind":"Name","value":"visceralFat"}},{"kind":"Field","name":{"kind":"Name","value":"waistCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHeightRatio"}},{"kind":"Field","name":{"kind":"Name","value":"hipCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHipRatio"}},{"kind":"Field","name":{"kind":"Name","value":"chestCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"thighCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bicepsCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"neckCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFatCaliper"}},{"kind":"Field","name":{"kind":"Name","value":"chestSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"abdominalSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"thighSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"basalMetabolicRate"}},{"kind":"Field","name":{"kind":"Name","value":"totalDailyEnergyExpenditure"}},{"kind":"Field","name":{"kind":"Name","value":"calories"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"saveHistory"}},{"kind":"Field","name":{"kind":"Name","value":"unitSystem"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toSend"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featuresEnabled"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"others"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"calendar"}},{"kind":"Field","name":{"kind":"Name","value":"collections"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"workouts"}},{"kind":"Field","name":{"kind":"Name","value":"measurements"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"anime"}},{"kind":"Field","name":{"kind":"Name","value":"audioBook"}},{"kind":"Field","name":{"kind":"Name","value":"book"}},{"kind":"Field","name":{"kind":"Name","value":"manga"}},{"kind":"Field","name":{"kind":"Name","value":"movie"}},{"kind":"Field","name":{"kind":"Name","value":"podcast"}},{"kind":"Field","name":{"kind":"Name","value":"show"}},{"kind":"Field","name":{"kind":"Name","value":"videoGame"}},{"kind":"Field","name":{"kind":"Name","value":"visualNovel"}},{"kind":"Field","name":{"kind":"Name","value":"people"}},{"kind":"Field","name":{"kind":"Name","value":"groups"}},{"kind":"Field","name":{"kind":"Name","value":"genres"}}]}}]}}]}}]}}]} as unknown as DocumentNode<UserPreferencesQuery, UserPreferencesQueryVariables>;
+export const UserPreferencesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserPreferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userPreferences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"general"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reviewScale"}},{"kind":"Field","name":{"kind":"Name","value":"displayNsfw"}},{"kind":"Field","name":{"kind":"Name","value":"disableVideos"}},{"kind":"Field","name":{"kind":"Name","value":"persistQueries"}},{"kind":"Field","name":{"kind":"Name","value":"watchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableReviews"}},{"kind":"Field","name":{"kind":"Name","value":"disableIntegrations"}},{"kind":"Field","name":{"kind":"Name","value":"disableWatchProviders"}},{"kind":"Field","name":{"kind":"Name","value":"disableNavigationAnimation"}},{"kind":"Field","name":{"kind":"Name","value":"dashboard"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"section"}},{"kind":"Field","name":{"kind":"Name","value":"hidden"}},{"kind":"Field","name":{"kind":"Name","value":"numElements"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"measurements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"custom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"dataType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"inbuilt"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"bodyMassIndex"}},{"kind":"Field","name":{"kind":"Name","value":"totalBodyWater"}},{"kind":"Field","name":{"kind":"Name","value":"muscle"}},{"kind":"Field","name":{"kind":"Name","value":"leanBodyMass"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFat"}},{"kind":"Field","name":{"kind":"Name","value":"boneMass"}},{"kind":"Field","name":{"kind":"Name","value":"visceralFat"}},{"kind":"Field","name":{"kind":"Name","value":"waistCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHeightRatio"}},{"kind":"Field","name":{"kind":"Name","value":"hipCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"waistToHipRatio"}},{"kind":"Field","name":{"kind":"Name","value":"chestCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"thighCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bicepsCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"neckCircumference"}},{"kind":"Field","name":{"kind":"Name","value":"bodyFatCaliper"}},{"kind":"Field","name":{"kind":"Name","value":"chestSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"abdominalSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"thighSkinfold"}},{"kind":"Field","name":{"kind":"Name","value":"basalMetabolicRate"}},{"kind":"Field","name":{"kind":"Name","value":"totalDailyEnergyExpenditure"}},{"kind":"Field","name":{"kind":"Name","value":"calories"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"saveHistory"}},{"kind":"Field","name":{"kind":"Name","value":"unitSystem"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toSend"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featuresEnabled"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"others"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"calendar"}},{"kind":"Field","name":{"kind":"Name","value":"collections"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fitness"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"workouts"}},{"kind":"Field","name":{"kind":"Name","value":"measurements"}}]}},{"kind":"Field","name":{"kind":"Name","value":"media"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"anime"}},{"kind":"Field","name":{"kind":"Name","value":"audioBook"}},{"kind":"Field","name":{"kind":"Name","value":"book"}},{"kind":"Field","name":{"kind":"Name","value":"manga"}},{"kind":"Field","name":{"kind":"Name","value":"movie"}},{"kind":"Field","name":{"kind":"Name","value":"podcast"}},{"kind":"Field","name":{"kind":"Name","value":"show"}},{"kind":"Field","name":{"kind":"Name","value":"videoGame"}},{"kind":"Field","name":{"kind":"Name","value":"visualNovel"}},{"kind":"Field","name":{"kind":"Name","value":"people"}},{"kind":"Field","name":{"kind":"Name","value":"groups"}},{"kind":"Field","name":{"kind":"Name","value":"genres"}}]}}]}}]}}]}}]} as unknown as DocumentNode<UserPreferencesQuery, UserPreferencesQueryVariables>;
 export const UserWorkoutsListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserWorkoutsList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SearchInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userWorkoutsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"nextPage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"startTime"}},{"kind":"Field","name":{"kind":"Name","value":"endTime"}},{"kind":"Field","name":{"kind":"Name","value":"summary"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSummaryPart"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutOrExerciseTotals"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personalBestsAchieved"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"restTime"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSetStatisticPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSetStatistic"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"oneRm"}},{"kind":"Field","name":{"kind":"Name","value":"pace"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSummaryPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSummary"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"numSets"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"bestSet"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"statistic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetStatisticPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"}}]}}]}}]}}]} as unknown as DocumentNode<UserWorkoutsListQuery, UserWorkoutsListQueryVariables>;
 export const WorkoutDetailsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"WorkoutDetails"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workoutId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workoutDetails"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workoutId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workoutId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CollectionPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"endTime"}},{"kind":"Field","name":{"kind":"Name","value":"startTime"}},{"kind":"Field","name":{"kind":"Name","value":"repeatedFrom"}},{"kind":"Field","name":{"kind":"Name","value":"summary"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSummaryPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"information"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutInformationPart"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutOrExerciseTotals"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personalBestsAchieved"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"restTime"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSetStatisticPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSetStatistic"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"distance"}},{"kind":"Field","name":{"kind":"Name","value":"reps"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"oneRm"}},{"kind":"Field","name":{"kind":"Name","value":"pace"}},{"kind":"Field","name":{"kind":"Name","value":"volume"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EntityAssetsPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EntityAssets"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"videos"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CollectionPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"userId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutSummaryPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutSummary"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"numSets"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"bestSet"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"statistic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetStatisticPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkoutInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkoutInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"assets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EntityAssetsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"exercises"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"notes"}},{"kind":"Field","name":{"kind":"Name","value":"restTime"}},{"kind":"Field","name":{"kind":"Name","value":"total"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutOrExerciseTotalsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"supersetWith"}},{"kind":"Field","name":{"kind":"Name","value":"assets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EntityAssetsPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"statistic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"WorkoutSetStatisticPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"note"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"personalBests"}},{"kind":"Field","name":{"kind":"Name","value":"confirmedAt"}}]}}]}}]}}]} as unknown as DocumentNode<WorkoutDetailsQuery, WorkoutDetailsQueryVariables>;
 export const GetOidcRedirectUrlDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOidcRedirectUrl"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getOidcRedirectUrl"}}]}}]} as unknown as DocumentNode<GetOidcRedirectUrlQuery, GetOidcRedirectUrlQueryVariables>;
@@ -3120,7 +3126,7 @@ export const GetPresignedS3UrlDocument = {"kind":"Document","definitions":[{"kin
 export const ProvidersLanguageInformationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProvidersLanguageInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"providersLanguageInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"supported"}},{"kind":"Field","name":{"kind":"Name","value":"default"}},{"kind":"Field","name":{"kind":"Name","value":"source"}}]}}]}}]} as unknown as DocumentNode<ProvidersLanguageInformationQuery, ProvidersLanguageInformationQueryVariables>;
 export const UserExportsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserExports"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userExports"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startedAt"}},{"kind":"Field","name":{"kind":"Name","value":"endedAt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"exported"}}]}}]}}]} as unknown as DocumentNode<UserExportsQuery, UserExportsQueryVariables>;
 export const UserCollectionsListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserCollectionsList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userCollectionsList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"isDefault"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"creator"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"collaborators"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"informationTemplate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"required"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}}]}}]}}]}}]} as unknown as DocumentNode<UserCollectionsListQuery, UserCollectionsListQueryVariables>;
-export const UserIntegrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"source"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"maximumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"minimumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"lastTriggeredOn"}}]}}]}}]} as unknown as DocumentNode<UserIntegrationsQuery, UserIntegrationsQueryVariables>;
+export const UserIntegrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userIntegrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"maximumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"minimumProgress"}},{"kind":"Field","name":{"kind":"Name","value":"lastTriggeredOn"}}]}}]}}]} as unknown as DocumentNode<UserIntegrationsQuery, UserIntegrationsQueryVariables>;
 export const UserNotificationPlatformsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserNotificationPlatforms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userNotificationPlatforms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode<UserNotificationPlatformsQuery, UserNotificationPlatformsQueryVariables>;
 export const UsersListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UsersList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usersList"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"lot"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isDisabled"}}]}}]}}]} as unknown as DocumentNode<UsersListQuery, UsersListQueryVariables>;
 export const UserUpcomingCalendarEventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserUpcomingCalendarEvents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserUpcomingCalendarEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userUpcomingCalendarEvents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CalendarEventPart"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenShowExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenShowExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}},{"kind":"Field","name":{"kind":"Name","value":"season"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SeenPodcastExtraInformation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"episode"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CalendarEventPart"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"GraphqlCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"metadataId"}},{"kind":"Field","name":{"kind":"Name","value":"metadataLot"}},{"kind":"Field","name":{"kind":"Name","value":"episodeName"}},{"kind":"Field","name":{"kind":"Name","value":"metadataTitle"}},{"kind":"Field","name":{"kind":"Name","value":"metadataImage"}},{"kind":"Field","name":{"kind":"Name","value":"calendarEventId"}},{"kind":"Field","name":{"kind":"Name","value":"showExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenShowExtraInformationPart"}}]}},{"kind":"Field","name":{"kind":"Name","value":"podcastExtraInformation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SeenPodcastExtraInformationPart"}}]}}]}}]} as unknown as DocumentNode<UserUpcomingCalendarEventsQuery, UserUpcomingCalendarEventsQueryVariables>;
diff --git a/libs/graphql/src/backend/queries/UserPreferences.gql b/libs/graphql/src/backend/queries/UserPreferences.gql
index 847638dbdb..1a4772e47a 100644
--- a/libs/graphql/src/backend/queries/UserPreferences.gql
+++ b/libs/graphql/src/backend/queries/UserPreferences.gql
@@ -7,8 +7,8 @@ query UserPreferences {
       persistQueries
       watchProviders
       disableReviews
+      disableIntegrations
       disableWatchProviders
-      disableYankIntegrations
       disableNavigationAnimation
       dashboard {
         section
diff --git a/libs/graphql/src/backend/queries/combined.gql b/libs/graphql/src/backend/queries/combined.gql
index 7c83080ca9..9c150c7ea8 100644
--- a/libs/graphql/src/backend/queries/combined.gql
+++ b/libs/graphql/src/backend/queries/combined.gql
@@ -63,7 +63,7 @@ query UserIntegrations {
   userIntegrations {
     id
     lot
-    source
+    provider
     createdOn
     isDisabled
     maximumProgress


Test patch: