Skip to content

Commit

Permalink
Komga implementation (#943)
Browse files Browse the repository at this point in the history
* komga implementation

* Updated Komga integration to use SSE

* Finalizing implementation

Cleaned up where some variables lived and documented important code.

Removed unused imports

Templatized duplicated code.

Switched to an unbounded channel to allow users to make any length of
background task polling periods.

* Added Komga Documentation

* Placed Cargo.toml in Alphabetic Order

* Changed Komga into a Yank Integration.

* Removed provider specifics as it wasnt really needed.

* Reverted order

* Updated komga documentation

* Fixed a bug where some manga have imported with the incorrect number

* docs: address formatting issues

* build(backend): pin `eventsource-stream` version

* chore(backend): format files

* refactor(backend): move integration to dedicated folder

* Fixed a bug where some tachiyomi clients report in random order.

* Removed provider specifics from UpdateUserInntegrationInput

* Fixed order of includes to match original.

* Fixed order of imports for komga.rs

* chore(backend): run formatter

* chore(backend): some housekeeping

* fix(backend): type checks

* chore(backend): add newline

* feat(backend): yank integrations data right on application startup

* chore(backend): add a debug statement

* Removed Option from find_provider_and_id

* Run CI Empty Commit

* chore: empty commit

[Run CI]

* ci: additional check for maintainer

* Komga Implementation

* Resolve merge errors

* ci: revert ci changes

* chore(integrations): import structure

* build(integrations): remove uneeded package

* ci: change computation of image names

Run CI.

* ci: hardcode docker username

Run CI.

* ci: enable hardmode

Run CI.

* ci: quote names

Run CI.

* ci: no heredoc fuckery

Run CI.

* ci: change name of image

Run CI.

* ci: remove docker for forks

Run CI.

* ci: update condition

Run CI.

* ci: logging

Run CI.

* ci: use gh actions script

Run CI.

* ci: print all outputs

Run CI.

* ci: use correct image names

Run CI.

* ci: use correct owner name

* Upgraded to a trait model

* Migrated jellyfin to trait

* Fixed visibility of function

* Emby Integration Migration

* Plex Integration Migration

* Audiobookshelf Integration Migration (partial)

* Kodi Integration Migration

* Sonarr Integration Migration

* Radarr Integration Migration

* Ran formatter

* chore: run rust formatter

* refactor(integrations): some import changes

* Finished implementing Audiobookshelf
Introduced YankIntegrationWithCommit trait to address issue with passing the closure through a staticly allocated enum.
Renamed the integration file to integration trait and moved all integrations traits to this file
Changed visibility of all integrations to be pub(crate) since they dont need to be accessible anywhere else.
Introduced proper error handling for improper integration types

* Undid accidental change

* chore(backend): apply formatter

---------

Co-authored-by: Diptesh Choudhuri <ignisda2001@gmail.com>
  • Loading branch information
Jacob-Tate and IgnisDa authored Aug 20, 2024
1 parent 62d2b43 commit f537c10
Show file tree
Hide file tree
Showing 25 changed files with 1,624 additions and 617 deletions.
76 changes: 48 additions & 28 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,56 @@ jobs:
pre-workflow-checks:
runs-on: ubuntu-latest
outputs:
should-run: ${{ steps.check.outputs.should-run }}
should-release: ${{ steps.tag.outputs.should-release }}
should-run: ${{ steps.set_outputs.outputs.should-run }}
image-names: ${{ steps.set_outputs.outputs.image-names }}
should-release: ${{ steps.set_outputs.outputs.should-release }}

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check commit message
id: check
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
echo "should-run=true" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
COMMIT_MSG=$(git log --format=%B ${{ github.event.pull_request.head.sha }})
if [[ "$COMMIT_MSG" == *"Run CI"* ]]; then
echo "should-run=true" >> $GITHUB_OUTPUT
else
echo "should-run=false" >> $GITHUB_OUTPUT
fi
else
echo "should-run=false" >> $GITHUB_OUTPUT
fi
- name: Check tag
id: tag
run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/tags/${{ github.ref_name }}" ]]; then
echo "should-release=true" >> $GITHUB_OUTPUT
else
echo "should-release=false" >> $GITHUB_OUTPUT
fi
- name: Set outputs
id: set_outputs
uses: actions/github-script@v7
with:
script: |
const repositoryName = context.payload.repository.name;
const owner = context.repo.owner;
const ghcrRegistry = process.env.GHCR_REGISTRY;
const dockerUsername = process.env.DOCKER_USERNAME;
let imageNames = [
`name=${dockerUsername}/${repositoryName}`,
`name=${ghcrRegistry}/${owner}/${repositoryName}`
];
if (context.eventName === "push") {
core.setOutput('should-run', 'true');
} else if (context.eventName === "pull_request") {
const commitMsg = await github.rest.repos.getCommit({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.payload.pull_request.head.sha
}).then(commit => commit.data.commit.message);
if (commitMsg.includes("Run CI")) {
core.setOutput('should-run', 'true');
if (context.payload.pull_request.head.repo.full_name !== context.repo.full_name) {
imageNames.shift();
}
} else {
core.setOutput('should-run', 'false');
}
} else {
core.setOutput('should-run', 'false');
}
if (context.eventName === "push" && context.ref.startsWith("refs/tags/")) {
core.setOutput('should-release', 'true');
} else {
core.setOutput('should-release', 'false');
}
core.setOutput('image-names', imageNames.join('\n'));
create-release:
needs:
Expand Down Expand Up @@ -187,22 +207,22 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Log in to the ghcr container registry
uses: docker/login-action@v3
continue-on-error: true
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to the docker hub container registry
uses: docker/login-action@v3
continue-on-error: true
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: |
name=${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}
name=${{ env.GHCR_REGISTRY }}/${{ github.repository_owner }}/${{ github.event.repository.name }}
images: ${{ needs.pre-workflow-checks.outputs.image-names }}
tags: |
type=ref,event=pr
type=raw,value=develop,enable={{is_default_branch}}
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions apps/backend/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ 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();
misc_service.sync_integrations_data().await.unwrap();
Ok(())
}

Expand Down Expand Up @@ -118,6 +117,7 @@ pub async fn perform_application_job(
.deploy_update_exercise_library_job()
.await
.is_ok(),
ApplicationJob::SyncIntegrationsData => misc_service.sync_integrations_data().await.is_ok(),
};
tracing::trace!(
"Job: {:#?}, Time Taken: {}ms, Successful = {}",
Expand Down
5 changes: 5 additions & 0 deletions apps/backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ async fn main() -> Result<()> {
)
.await;

perform_application_job_storage
.enqueue(ApplicationJob::SyncIntegrationsData)
.await
.unwrap();

if Exercise::find().count(&db).await? == 0 {
tracing::info!("Instance does not have exercises data. Deploying job to download them...");
perform_application_job_storage
Expand Down
38 changes: 37 additions & 1 deletion apps/frontend/app/routes/_dashboard.settings.integrations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
DeleteUserIntegrationDocument,
GenerateAuthTokenDocument,
IntegrationProvider,
MediaSource,
UpdateUserIntegrationDocument,
UserIntegrationsDocument,
type UserIntegrationsQuery,
Expand All @@ -53,7 +54,10 @@ import { commaDelimitedString, dayjsLib } from "~/lib/generals";
import { useConfirmSubmit, useUserCollections } from "~/lib/hooks";
import { createToastHeaders, serverGqlService } from "~/lib/utilities.server";

const YANK_INTEGRATIONS = [IntegrationProvider.Audiobookshelf];
const YANK_INTEGRATIONS = [
IntegrationProvider.Audiobookshelf,
IntegrationProvider.Komga,
];
const PUSH_INTEGRATIONS = [
IntegrationProvider.Radarr,
IntegrationProvider.Sonarr,
Expand Down Expand Up @@ -154,6 +158,10 @@ const createSchema = z.object({
plexUsername: z.string().optional(),
audiobookshelfBaseUrl: z.string().optional(),
audiobookshelfToken: z.string().optional(),
komgaBaseUrl: z.string().optional(),
komgaUsername: z.string().optional(),
komgaPassword: z.string().optional(),
komgaProvider: z.nativeEnum(MediaSource).optional(),
radarrBaseUrl: z.string().optional(),
radarrApiKey: z.string().optional(),
radarrProfileId: z.number().optional(),
Expand Down Expand Up @@ -438,6 +446,34 @@ const CreateIntegrationModal = (props: {
/>
</>
))
.with(IntegrationProvider.Komga, () => (
<>
<TextInput
label="Base Url"
required
name="providerSpecifics.komgaBaseUrl"
/>
<TextInput
label="Username"
required
name="providerSpecifics.komgaUsername"
/>
<TextInput
label="Password"
required
name="providerSpecifics.komgaPassword"
/>
<Select
label="Select a provider"
name="providerSpecifics.komgaProvider"
required
data={[MediaSource.Anilist, MediaSource.Mal].map((is) => ({
label: changeCase(is),
value: is,
}))}
/>
</>
))
.with(IntegrationProvider.Plex, () => (
<>
<TextInput
Expand Down
1 change: 1 addition & 0 deletions crates/background/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum ApplicationJob {
RecalculateUserSummary(String),
PerformBackgroundTasks,
UpdateExerciseLibrary,
SyncIntegrationsData,
}

impl Message for ApplicationJob {
Expand Down
1 change: 1 addition & 0 deletions crates/enums/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ pub enum IntegrationProvider {
Kodi,
Radarr,
Sonarr,
Komga,
}

#[derive(
Expand Down
2 changes: 1 addition & 1 deletion crates/migrations/src/m20230505_create_review.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sea_orm_migration::prelude::*;
use enums::Visibility;
use sea_orm_migration::prelude::*;

use super::{
m20230410_create_metadata::Metadata, m20230413_create_person::Person,
Expand Down
6 changes: 5 additions & 1 deletion crates/models/media/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{collections::HashSet, fmt, sync::Arc};

use async_graphql::{Enum, InputObject, InputType, OneofObject, SimpleObject, Union};
use boilermates::boilermates;
use chrono::{DateTime, NaiveDate,NaiveDateTime};
use chrono::{DateTime, NaiveDate, NaiveDateTime};
use common_models::{
CollectionExtraInformation, IdAndNamedObject, SearchInput, StoredUrl, StringIdObject,
};
Expand Down Expand Up @@ -911,6 +911,10 @@ pub struct IntegrationProviderSpecifics {
pub plex_username: Option<String>,
pub audiobookshelf_base_url: Option<String>,
pub audiobookshelf_token: Option<String>,
pub komga_base_url: Option<String>,
pub komga_username: Option<String>,
pub komga_password: Option<String>,
pub komga_provider: Option<MediaSource>,
pub radarr_base_url: Option<String>,
pub radarr_api_key: Option<String>,
pub radarr_profile_id: Option<i32>,
Expand Down
9 changes: 7 additions & 2 deletions crates/providers/src/manga_updates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,12 @@ struct MetadataSearchResponse<T> {
}

impl MangaUpdatesService {
fn extract_status(&self, input: &str) -> (Option<i32>, Option<String>) {
fn extract_status(&self, input: Option<String>) -> (Option<i32>, Option<String>) {
if input.is_none() {
return (None, None);
}

let input = input.unwrap();
let first_part = input.split("<BR>").next().unwrap_or("").trim();
let parts: Vec<&str> = first_part.split_whitespace().collect();

Expand Down Expand Up @@ -324,7 +329,7 @@ impl MediaProvider for MangaUpdatesService {
}
}

let (volumes, status) = self.extract_status(&data.status.clone().unwrap());
let (volumes, status) = self.extract_status(data.status.clone());

Ok(MediaDetails {
identifier: data.series_id.unwrap().to_string(),
Expand Down
2 changes: 2 additions & 0 deletions crates/services/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ anyhow = { workspace = true }
application-utils = { path = "../../utils/application" }
async-graphql = { workspace = true }
enums = { path = "../../enums" }
eventsource-stream = "=0.2.3"
database-models = { path = "../../models/database" }
database-utils = { path = "../../utils/database" }
media-models = { path = "../../models/media" }
Expand All @@ -23,5 +24,6 @@ serde = { workspace = true }
serde_json = { workspace = true }
sonarr-api-rs = "=3.0.0"
specific-models = { path = "../../models/specific" }
tokio = "1.39.2"
tracing = { workspace = true }
traits = { path = "../../traits" }
Loading

0 comments on commit f537c10

Please sign in to comment.