refactor-architecture #27

Merged
rov merged 11 commits from refactor-architecture into main 2026-03-18 16:55:37 -03:00
41 changed files with 244 additions and 229 deletions
Showing only changes of commit d845dc4d12 - Show all commits

View File

@ -1,26 +0,0 @@
package com.magamochi.controller;
import com.magamochi.common.dto.DefaultResponseDTO;
import com.magamochi.model.dto.ProviderListDTO;
import com.magamochi.service.ProviderService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/providers")
@RequiredArgsConstructor
public class ProviderController {
private final ProviderService providerService;
@Operation(
summary = "Get a list of providers",
description = "Retrieve a list of content providers",
tags = {"Provider"},
operationId = "getProviders")
@GetMapping
public DefaultResponseDTO<ProviderListDTO> getMangas(
@RequestParam(name = "manualImport", required = false) Boolean manualImport) {
return DefaultResponseDTO.ok(providerService.getProviders(manualImport));
}
}

View File

@ -0,0 +1,29 @@
package com.magamochi.ingestion.controller;
import com.magamochi.common.dto.DefaultResponseDTO;
import com.magamochi.ingestion.model.dto.ContentProviderListDTO;
import com.magamochi.ingestion.service.ContentProviderService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ingestion")
@RequiredArgsConstructor
public class IngestionController {
private final ContentProviderService contentProviderService;
@Operation(
summary = "Get a list of content providers",
description = "Retrieve a list of content providers",
tags = {"Ingestion"},
operationId = "getContentProviders")
@GetMapping("/providers")
public DefaultResponseDTO<ContentProviderListDTO> getContentProviders(
@RequestParam(name = "manualImport", required = false) Boolean manualImport) {
return DefaultResponseDTO.ok(contentProviderService.getProviders(manualImport));
}
}

View File

@ -0,0 +1,19 @@
package com.magamochi.ingestion.model.dto;
import com.magamochi.ingestion.model.entity.ContentProvider;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.List;
public record ContentProviderListDTO(@NotNull List<ContentProviderDTO> providers) {
public static ContentProviderListDTO from(List<ContentProvider> contentProviders) {
return new ContentProviderListDTO(
contentProviders.stream().map(ContentProviderDTO::from).toList());
}
record ContentProviderDTO(long id, @NotBlank String name) {
public static ContentProviderDTO from(ContentProvider contentProvider) {
return new ContentProviderDTO(contentProvider.getId(), contentProvider.getName());
}
}
}

View File

@ -1,6 +1,6 @@
package com.magamochi.model.entity; package com.magamochi.ingestion.model.entity;
import com.magamochi.model.enumeration.ProviderStatus; import com.magamochi.model.entity.MangaContentProvider;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
@ -9,30 +9,29 @@ import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.annotations.UpdateTimestamp;
@Entity @Entity
@Table(name = "providers") @Table(name = "content_providers")
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
@Setter @Setter
public class Provider { public class ContentProvider {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
private String name; private String name;
@Enumerated(EnumType.STRING) private boolean active;
private ProviderStatus status;
private Boolean supportsChapterFetch;
private Boolean manualImport;
@CreationTimestamp private Instant createdAt; @CreationTimestamp private Instant createdAt;
@UpdateTimestamp private Instant updatedAt; @UpdateTimestamp private Instant updatedAt;
@OneToMany(mappedBy = "provider") @OneToMany(mappedBy = "contentProvider")
private List<MangaProvider> mangaProviders; private List<MangaContentProvider> mangaContentProviders;
@Builder.Default private Boolean supportsChapterFetch = true;
@Builder.Default private Boolean manualImport = false;
} }

View File

@ -1,4 +1,4 @@
package com.magamochi.model.entity; package com.magamochi.ingestion.model.entity;
import java.time.Instant; import java.time.Instant;
import lombok.Builder; import lombok.Builder;

View File

@ -0,0 +1,9 @@
package com.magamochi.ingestion.model.repository;
import com.magamochi.ingestion.model.entity.ContentProvider;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ContentProviderRepository extends JpaRepository<ContentProvider, Long> {
Optional<ContentProvider> findByNameIgnoreCase(String name);
}

View File

@ -0,0 +1,25 @@
package com.magamochi.ingestion.service;
import static java.util.Objects.nonNull;
import com.magamochi.ingestion.model.dto.ContentProviderListDTO;
import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.ingestion.model.repository.ContentProviderRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class ContentProviderService {
private final ContentProviderRepository contentProviderRepository;
public ContentProviderListDTO getProviders(Boolean manualImport) {
var providers = contentProviderRepository.findAll();
if (nonNull(manualImport) && manualImport) {
providers = providers.stream().filter(ContentProvider::getManualImport).toList();
}
return ContentProviderListDTO.from(providers);
}
}

View File

@ -1,4 +1,4 @@
package com.magamochi.service; package com.magamochi.ingestion.service;
import com.magamochi.client.FlareClient; import com.magamochi.client.FlareClient;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -1,10 +1,10 @@
package com.magamochi.service; package com.magamochi.ingestion.service;
import static java.util.Objects.isNull; import static java.util.Objects.isNull;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import com.magamochi.client.FlareClient; import com.magamochi.client.FlareClient;
import com.magamochi.model.entity.FlareSession; import com.magamochi.ingestion.model.entity.FlareSession;
import com.magamochi.registry.FlareSessionRegistry; import com.magamochi.registry.FlareSessionRegistry;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;

View File

@ -1,4 +1,4 @@
package com.magamochi.task; package com.magamochi.ingestion.task;
import com.magamochi.client.FlareClient; import com.magamochi.client.FlareClient;
import com.magamochi.registry.FlareSessionRegistry; import com.magamochi.registry.FlareSessionRegistry;

View File

@ -1,4 +1,4 @@
package com.magamochi.task; package com.magamochi.ingestion.task;
import com.magamochi.client.FlareClient; import com.magamochi.client.FlareClient;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -16,7 +16,7 @@ public record ImportReviewDTO(
return new ImportReviewDTO( return new ImportReviewDTO(
review.getId(), review.getId(),
review.getTitle(), review.getTitle(),
review.getProvider().getName(), review.getContentProvider().getName(),
review.getUrl(), review.getUrl(),
"Title match not found", "Title match not found",
review.getCreatedAt()); review.getCreatedAt());

View File

@ -5,8 +5,7 @@ import static java.util.Objects.isNull;
import com.magamochi.model.entity.Manga; import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaAlternativeTitle; import com.magamochi.model.entity.MangaAlternativeTitle;
import com.magamochi.model.entity.MangaChapter; import com.magamochi.model.entity.MangaChapter;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.enumeration.ProviderStatus;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
@ -38,38 +37,38 @@ public record MangaDTO(
manga.getPublishedFrom(), manga.getPublishedFrom(),
manga.getPublishedTo(), manga.getPublishedTo(),
manga.getSynopsis(), manga.getSynopsis(),
manga.getMangaProviders().size(), manga.getMangaContentProviders().size(),
manga.getAlternativeTitles().stream().map(MangaAlternativeTitle::getTitle).toList(), manga.getAlternativeTitles().stream().map(MangaAlternativeTitle::getTitle).toList(),
manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(), manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(),
manga.getMangaAuthors().stream() manga.getMangaAuthors().stream()
.map(mangaAuthor -> mangaAuthor.getAuthor().getName()) .map(mangaAuthor -> mangaAuthor.getAuthor().getName())
.toList(), .toList(),
manga.getScore(), manga.getScore(),
manga.getMangaProviders().stream().map(MangaProviderDTO::from).toList(), manga.getMangaContentProviders().stream().map(MangaProviderDTO::from).toList(),
manga.getChapterCount(), manga.getChapterCount(),
favorite, favorite,
following); following);
} }
public record MangaProviderDTO( public record MangaProviderDTO(
@NotNull long id, long id,
@NotBlank String providerName, @NotBlank String providerName,
@NotNull ProviderStatus providerStatus, boolean active,
@NotNull Integer chaptersAvailable, @NotNull Integer chaptersAvailable,
@NotNull Integer chaptersDownloaded, @NotNull Integer chaptersDownloaded,
@NotNull Boolean supportsChapterFetch) { @NotNull Boolean supportsChapterFetch) {
public static MangaProviderDTO from(MangaProvider mangaProvider) { public static MangaProviderDTO from(MangaContentProvider mangaContentProvider) {
var chapters = mangaProvider.getMangaChapters(); var chapters = mangaContentProvider.getMangaChapters();
var chaptersAvailable = chapters.size(); var chaptersAvailable = chapters.size();
var chaptersDownloaded = (int) chapters.stream().filter(MangaChapter::getDownloaded).count(); var chaptersDownloaded = (int) chapters.stream().filter(MangaChapter::getDownloaded).count();
return new MangaProviderDTO( return new MangaProviderDTO(
mangaProvider.getId(), mangaContentProvider.getId(),
mangaProvider.getProvider().getName(), mangaContentProvider.getContentProvider().getName(),
mangaProvider.getProvider().getStatus(), mangaContentProvider.getContentProvider().isActive(),
chaptersAvailable, chaptersAvailable,
chaptersDownloaded, chaptersDownloaded,
mangaProvider.getProvider().getSupportsChapterFetch()); mangaContentProvider.getContentProvider().getSupportsChapterFetch());
} }
} }
} }

View File

@ -28,7 +28,7 @@ public record MangaListDTO(
manga.getStatus(), manga.getStatus(),
manga.getPublishedFrom(), manga.getPublishedFrom(),
manga.getPublishedTo(), manga.getPublishedTo(),
manga.getMangaProviders().size(), manga.getMangaContentProviders().size(),
manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(), manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(),
manga.getMangaAuthors().stream() manga.getMangaAuthors().stream()
.map(mangaAuthor -> mangaAuthor.getAuthor().getName()) .map(mangaAuthor -> mangaAuthor.getAuthor().getName())

View File

@ -1,17 +0,0 @@
package com.magamochi.model.dto;
import com.magamochi.model.entity.Provider;
import jakarta.validation.constraints.NotNull;
import java.util.List;
public record ProviderListDTO(@NotNull List<ProviderDTO> providers) {
public static ProviderListDTO from(List<Provider> providers) {
return new ProviderListDTO(providers.stream().map(ProviderDTO::from).toList());
}
record ProviderDTO(@NotNull Long id, @NotNull String name) {
public static ProviderDTO from(Provider provider) {
return new ProviderDTO(provider.getId(), provider.getName());
}
}
}

View File

@ -35,7 +35,7 @@ public class Manga {
@UpdateTimestamp private Instant updatedAt; @UpdateTimestamp private Instant updatedAt;
@OneToMany(mappedBy = "manga") @OneToMany(mappedBy = "manga")
private List<MangaProvider> mangaProviders; private List<MangaContentProvider> mangaContentProviders;
@ManyToOne @ManyToOne
@JoinColumn(name = "cover_image_id") @JoinColumn(name = "cover_image_id")

View File

@ -20,8 +20,8 @@ public class MangaChapter {
private Long id; private Long id;
@ManyToOne @ManyToOne
@JoinColumn(name = "manga_provider_id") @JoinColumn(name = "manga_content_provider_id")
private MangaProvider mangaProvider; private MangaContentProvider mangaContentProvider;
private String title; private String title;

View File

@ -1,5 +1,6 @@
package com.magamochi.model.entity; package com.magamochi.model.entity;
import com.magamochi.ingestion.model.entity.ContentProvider;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
@ -8,13 +9,13 @@ import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.annotations.UpdateTimestamp;
@Entity @Entity
@Table(name = "manga_provider") @Table(name = "manga_content_provider")
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
@Setter @Setter
public class MangaProvider { public class MangaContentProvider {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
@ -24,14 +25,14 @@ public class MangaProvider {
private Manga manga; private Manga manga;
@ManyToOne @ManyToOne
@JoinColumn(name = "provider_id", nullable = false) @JoinColumn(name = "content_provider_id", nullable = false)
private Provider provider; private ContentProvider contentProvider;
private String mangaTitle; private String mangaTitle;
private String url; private String url;
@OneToMany(mappedBy = "mangaProvider") @OneToMany(mappedBy = "mangaContentProvider")
List<MangaChapter> mangaChapters; List<MangaChapter> mangaChapters;
@CreationTimestamp private Instant createdAt; @CreationTimestamp private Instant createdAt;

View File

@ -1,5 +1,6 @@
package com.magamochi.model.entity; package com.magamochi.model.entity;
import com.magamochi.ingestion.model.entity.ContentProvider;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.Instant; import java.time.Instant;
import lombok.*; import lombok.*;
@ -22,8 +23,8 @@ public class MangaImportReview {
private String url; private String url;
@ManyToOne @ManyToOne
@JoinColumn(name = "provider_id") @JoinColumn(name = "content_provider_id")
private Provider provider; private ContentProvider contentProvider;
@CreationTimestamp private Instant createdAt; @CreationTimestamp private Instant createdAt;
} }

View File

@ -1,6 +0,0 @@
package com.magamochi.model.enumeration;
public enum ProviderStatus {
ACTIVE,
INACTIVE
}

View File

@ -1,15 +1,15 @@
package com.magamochi.model.repository; package com.magamochi.model.repository;
import com.magamochi.model.entity.MangaChapter; import com.magamochi.model.entity.MangaChapter;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface MangaChapterRepository extends JpaRepository<MangaChapter, Long> { public interface MangaChapterRepository extends JpaRepository<MangaChapter, Long> {
Optional<MangaChapter> findByMangaProviderAndUrlIgnoreCase( Optional<MangaChapter> findByMangaContentProviderAndUrlIgnoreCase(
MangaProvider mangaProvider, @NotBlank String url); MangaContentProvider mangaContentProvider, @NotBlank String url);
List<MangaChapter> findByMangaProviderId(Long mangaProvider_id); List<MangaChapter> findByMangaContentProviderId(Long mangaProvider_id);
} }

View File

@ -0,0 +1,15 @@
package com.magamochi.model.repository;
import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaContentProvider;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MangaContentProviderRepository extends JpaRepository<MangaContentProvider, Long> {
boolean existsByMangaAndContentProviderAndUrlIgnoreCase(
Manga manga, ContentProvider contentProvider, String url);
Optional<MangaContentProvider> findByMangaTitleIgnoreCaseAndContentProvider(
String mangaTitle, ContentProvider contentProvider);
}

View File

@ -1,14 +0,0 @@
package com.magamochi.model.repository;
import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaProvider;
import com.magamochi.model.entity.Provider;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MangaProviderRepository extends JpaRepository<MangaProvider, Long> {
boolean existsByMangaAndProviderAndUrlIgnoreCase(Manga manga, Provider provider, String url);
Optional<MangaProvider> findByMangaTitleIgnoreCaseAndProvider(
String mangaTitle, Provider provider);
}

View File

@ -1,9 +0,0 @@
package com.magamochi.model.repository;
import com.magamochi.model.entity.Provider;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProviderRepository extends JpaRepository<Provider, Long> {
Optional<Provider> findByNameIgnoreCase(String name);
}

View File

@ -1,6 +1,6 @@
package com.magamochi.registry; package com.magamochi.registry;
import com.magamochi.model.entity.FlareSession; import com.magamochi.ingestion.model.entity.FlareSession;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter; import lombok.Getter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;

View File

@ -46,8 +46,9 @@ public class MangaChapterService {
public void fetchChapter(Long chapterId) { public void fetchChapter(Long chapterId) {
var chapter = getMangaChapterThrowIfNotFound(chapterId); var chapter = getMangaChapterThrowIfNotFound(chapterId);
var mangaProvider = chapter.getMangaProvider(); var mangaProvider = chapter.getMangaContentProvider();
var provider = contentProviderFactory.getContentProvider(mangaProvider.getProvider().getName()); var provider =
contentProviderFactory.getContentProvider(mangaProvider.getContentProvider().getName());
var chapterImagesUrls = provider.getChapterImagesUrls(chapter.getUrl()); var chapterImagesUrls = provider.getChapterImagesUrls(chapter.getUrl());
if (chapterImagesUrls.isEmpty()) { if (chapterImagesUrls.isEmpty()) {
@ -99,7 +100,7 @@ public class MangaChapterService {
"Downloaded image {}/{} for manga {} chapter {}: {}", "Downloaded image {}/{} for manga {} chapter {}: {}",
entry.getKey() + 1, entry.getKey() + 1,
chapterImagesUrls.size(), chapterImagesUrls.size(),
chapter.getMangaProvider().getManga().getTitle(), chapter.getMangaContentProvider().getManga().getTitle(),
chapterId, chapterId,
entry.getValue()); entry.getValue());
@ -127,7 +128,7 @@ public class MangaChapterService {
var chapter = getMangaChapterThrowIfNotFound(chapterId); var chapter = getMangaChapterThrowIfNotFound(chapterId);
var chapters = var chapters =
chapter.getMangaProvider().getMangaChapters().stream() chapter.getMangaContentProvider().getMangaChapters().stream()
.sorted(Comparator.comparing(MangaChapter::getId)) .sorted(Comparator.comparing(MangaChapter::getId))
.toList(); .toList();
Long prevId = null; Long prevId = null;

View File

@ -5,11 +5,11 @@ import static java.util.Objects.nonNull;
import com.google.common.util.concurrent.RateLimiter; import com.google.common.util.concurrent.RateLimiter;
import com.magamochi.client.AniListClient; import com.magamochi.client.AniListClient;
import com.magamochi.client.JikanClient; import com.magamochi.client.JikanClient;
import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.model.dto.TitleMatchRequestDTO; import com.magamochi.model.dto.TitleMatchRequestDTO;
import com.magamochi.model.dto.UpdateMangaDataCommand; import com.magamochi.model.dto.UpdateMangaDataCommand;
import com.magamochi.model.entity.Manga; import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaImportReview; import com.magamochi.model.entity.MangaImportReview;
import com.magamochi.model.entity.Provider;
import com.magamochi.model.repository.MangaImportReviewRepository; import com.magamochi.model.repository.MangaImportReviewRepository;
import com.magamochi.model.repository.MangaRepository; import com.magamochi.model.repository.MangaRepository;
import com.magamochi.queue.UpdateMangaDataProducer; import com.magamochi.queue.UpdateMangaDataProducer;
@ -33,7 +33,7 @@ public class MangaCreationService {
private final UpdateMangaDataProducer updateMangaDataProducer; private final UpdateMangaDataProducer updateMangaDataProducer;
public Manga getOrCreateManga(String title, String url, Provider provider) { public Manga getOrCreateManga(String title, String url, ContentProvider contentProvider) {
var existingManga = mangaRepository.findByTitleIgnoreCase(title); var existingManga = mangaRepository.findByTitleIgnoreCase(title);
if (existingManga.isPresent()) { if (existingManga.isPresent()) {
return existingManga.get(); return existingManga.get();
@ -42,7 +42,7 @@ public class MangaCreationService {
jikanRateLimiter.acquire(); jikanRateLimiter.acquire();
var jikanResults = jikanClient.mangaSearch(title).data(); var jikanResults = jikanClient.mangaSearch(title).data();
if (jikanResults.isEmpty()) { if (jikanResults.isEmpty()) {
createMangaImportReview(title, url, provider); createMangaImportReview(title, url, contentProvider);
log.warn("No manga found with title {}", title); log.warn("No manga found with title {}", title);
return null; return null;
} }
@ -61,7 +61,7 @@ public class MangaCreationService {
.build()); .build());
if (!titleMatchResponse.isMatchFound()) { if (!titleMatchResponse.isMatchFound()) {
createMangaImportReview(title, url, provider); createMangaImportReview(title, url, contentProvider);
log.warn("No match found for manga with title {}", title); log.warn("No match found for manga with title {}", title);
return null; return null;
} }
@ -76,7 +76,7 @@ public class MangaCreationService {
.contains(titleMatchResponse.getBestMatch())) .contains(titleMatchResponse.getBestMatch()))
.findFirst(); .findFirst();
if (resultOptional.isEmpty()) { if (resultOptional.isEmpty()) {
createMangaImportReview(title, url, provider); createMangaImportReview(title, url, contentProvider);
log.warn("No match found for manga with title {}", title); log.warn("No match found for manga with title {}", title);
return null; return null;
} }
@ -152,12 +152,12 @@ public class MangaCreationService {
}); });
} }
private void createMangaImportReview(String title, String url, Provider provider) { private void createMangaImportReview(String title, String url, ContentProvider contentProvider) {
if (mangaImportReviewRepository.existsByTitleIgnoreCaseAndUrlIgnoreCase(title, url)) { if (mangaImportReviewRepository.existsByTitleIgnoreCaseAndUrlIgnoreCase(title, url)) {
return; return;
} }
mangaImportReviewRepository.save( mangaImportReviewRepository.save(
MangaImportReview.builder().title(title).url(url).provider(provider).build()); MangaImportReview.builder().title(title).url(url).contentProvider(contentProvider).build());
} }
} }

View File

@ -8,10 +8,10 @@ import com.magamochi.common.exception.NotFoundException;
import com.magamochi.model.dto.ImportReviewDTO; import com.magamochi.model.dto.ImportReviewDTO;
import com.magamochi.model.dto.UpdateMangaDataCommand; import com.magamochi.model.dto.UpdateMangaDataCommand;
import com.magamochi.model.entity.Manga; import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.entity.MangaImportReview; import com.magamochi.model.entity.MangaImportReview;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.repository.MangaContentProviderRepository;
import com.magamochi.model.repository.MangaImportReviewRepository; import com.magamochi.model.repository.MangaImportReviewRepository;
import com.magamochi.model.repository.MangaProviderRepository;
import com.magamochi.model.repository.MangaRepository; import com.magamochi.model.repository.MangaRepository;
import com.magamochi.queue.UpdateMangaDataProducer; import com.magamochi.queue.UpdateMangaDataProducer;
import java.util.List; import java.util.List;
@ -23,7 +23,7 @@ import org.springframework.stereotype.Service;
public class MangaImportReviewService { public class MangaImportReviewService {
private final MangaImportReviewRepository mangaImportReviewRepository; private final MangaImportReviewRepository mangaImportReviewRepository;
private final MangaRepository mangaRepository; private final MangaRepository mangaRepository;
private final MangaProviderRepository mangaProviderRepository; private final MangaContentProviderRepository mangaContentProviderRepository;
private final JikanClient jikanClient; private final JikanClient jikanClient;
@ -62,13 +62,13 @@ public class MangaImportReviewService {
.malId(Long.parseLong(malId)) .malId(Long.parseLong(malId))
.build())); .build()));
if (!mangaProviderRepository.existsByMangaAndProviderAndUrlIgnoreCase( if (!mangaContentProviderRepository.existsByMangaAndContentProviderAndUrlIgnoreCase(
manga, importReview.getProvider(), importReview.getUrl())) { manga, importReview.getContentProvider(), importReview.getUrl())) {
mangaProviderRepository.save( mangaContentProviderRepository.save(
MangaProvider.builder() MangaContentProvider.builder()
.manga(manga) .manga(manga)
.mangaTitle(importReview.getTitle()) .mangaTitle(importReview.getTitle())
.provider(importReview.getProvider()) .contentProvider(importReview.getContentProvider())
.url(importReview.getUrl()) .url(importReview.getUrl())
.build()); .build());
} }

View File

@ -7,6 +7,7 @@ import com.google.common.util.concurrent.RateLimiter;
import com.magamochi.client.AniListClient; import com.magamochi.client.AniListClient;
import com.magamochi.client.JikanClient; import com.magamochi.client.JikanClient;
import com.magamochi.common.exception.NotFoundException; import com.magamochi.common.exception.NotFoundException;
import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.entity.*; import com.magamochi.model.entity.*;
import com.magamochi.model.repository.*; import com.magamochi.model.repository.*;
@ -40,7 +41,7 @@ public class MangaImportService {
private final GenreRepository genreRepository; private final GenreRepository genreRepository;
private final MangaGenreRepository mangaGenreRepository; private final MangaGenreRepository mangaGenreRepository;
private final MangaProviderRepository mangaProviderRepository; private final MangaContentProviderRepository mangaContentProviderRepository;
private final AuthorRepository authorRepository; private final AuthorRepository authorRepository;
private final MangaAuthorRepository mangaAuthorRepository; private final MangaAuthorRepository mangaAuthorRepository;
private final MangaChapterRepository mangaChapterRepository; private final MangaChapterRepository mangaChapterRepository;
@ -368,13 +369,13 @@ public class MangaImportService {
} }
public MangaChapter persistMangaChapter( public MangaChapter persistMangaChapter(
MangaProvider mangaProvider, ContentProviderMangaChapterResponseDTO chapter) { MangaContentProvider mangaContentProvider, ContentProviderMangaChapterResponseDTO chapter) {
var mangaChapter = var mangaChapter =
mangaChapterRepository mangaChapterRepository
.findByMangaProviderAndUrlIgnoreCase(mangaProvider, chapter.chapterUrl()) .findByMangaContentProviderAndUrlIgnoreCase(mangaContentProvider, chapter.chapterUrl())
.orElseGet(MangaChapter::new); .orElseGet(MangaChapter::new);
mangaChapter.setMangaProvider(mangaProvider); mangaChapter.setMangaContentProvider(mangaContentProvider);
mangaChapter.setTitle(chapter.chapterTitle()); mangaChapter.setTitle(chapter.chapterTitle());
mangaChapter.setUrl(chapter.chapterUrl()); mangaChapter.setUrl(chapter.chapterUrl());
@ -388,26 +389,27 @@ public class MangaImportService {
log.warn( log.warn(
"Could not parse chapter number {} from manga {}", "Could not parse chapter number {} from manga {}",
chapter.chapter(), chapter.chapter(),
mangaProvider.getManga().getTitle()); mangaContentProvider.getManga().getTitle());
} }
} }
return mangaChapterRepository.save(mangaChapter); return mangaChapterRepository.save(mangaChapter);
} }
private MangaProvider getOrCreateMangaProvider(String title, Provider provider) { private MangaContentProvider getOrCreateMangaProvider(
return mangaProviderRepository String title, ContentProvider contentProvider) {
.findByMangaTitleIgnoreCaseAndProvider(title, provider) return mangaContentProviderRepository
.findByMangaTitleIgnoreCaseAndContentProvider(title, contentProvider)
.orElseGet( .orElseGet(
() -> { () -> {
jikanRateLimiter.acquire(); jikanRateLimiter.acquire();
var manga = mangaCreationService.getOrCreateManga(title, "manual", provider); var manga = mangaCreationService.getOrCreateManga(title, "manual", contentProvider);
return mangaProviderRepository.save( return mangaContentProviderRepository.save(
MangaProvider.builder() MangaContentProvider.builder()
.manga(manga) .manga(manga)
.mangaTitle(manga.getTitle()) .mangaTitle(manga.getTitle())
.provider(provider) .contentProvider(contentProvider)
.url("manual") .url("manual")
.build()); .build());
}); });

View File

@ -2,8 +2,8 @@ package com.magamochi.service;
import static java.util.Objects.isNull; import static java.util.Objects.isNull;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.repository.MangaProviderRepository; import com.magamochi.model.repository.MangaContentProviderRepository;
import com.magamochi.service.providers.PagedContentProviderFactory; import com.magamochi.service.providers.PagedContentProviderFactory;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -17,7 +17,7 @@ public class MangaListService {
private final MangaCreationService mangaCreationService; private final MangaCreationService mangaCreationService;
private final PagedContentProviderFactory pagedContentProviderFactory; private final PagedContentProviderFactory pagedContentProviderFactory;
private final MangaProviderRepository mangaProviderRepository; private final MangaContentProviderRepository mangaContentProviderRepository;
public void updateMangaList(String contentProviderName, Integer page) { public void updateMangaList(String contentProviderName, Integer page) {
var contentProvider = pagedContentProviderFactory.getPagedContentProvider(contentProviderName); var contentProvider = pagedContentProviderFactory.getPagedContentProvider(contentProviderName);
@ -28,7 +28,7 @@ public class MangaListService {
mangas.forEach( mangas.forEach(
mangaResponse -> { mangaResponse -> {
var mangaProvider = var mangaProvider =
mangaProviderRepository.findByMangaTitleIgnoreCaseAndProvider( mangaContentProviderRepository.findByMangaTitleIgnoreCaseAndContentProvider(
mangaResponse.title(), provider); mangaResponse.title(), provider);
if (mangaProvider.isPresent()) { if (mangaProvider.isPresent()) {
@ -43,13 +43,13 @@ public class MangaListService {
return; return;
} }
if (!mangaProviderRepository.existsByMangaAndProviderAndUrlIgnoreCase( if (!mangaContentProviderRepository.existsByMangaAndContentProviderAndUrlIgnoreCase(
manga, provider, mangaResponse.url())) { manga, provider, mangaResponse.url())) {
mangaProviderRepository.save( mangaContentProviderRepository.save(
MangaProvider.builder() MangaContentProvider.builder()
.manga(manga) .manga(manga)
.mangaTitle(mangaResponse.title()) .mangaTitle(mangaResponse.title())
.provider(provider) .contentProvider(provider)
.url(mangaResponse.url()) .url(mangaResponse.url())
.build()); .build());
} }

View File

@ -7,7 +7,7 @@ import com.magamochi.common.exception.NotFoundException;
import com.magamochi.model.dto.*; import com.magamochi.model.dto.*;
import com.magamochi.model.entity.Manga; import com.magamochi.model.entity.Manga;
import com.magamochi.model.entity.MangaChapter; import com.magamochi.model.entity.MangaChapter;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.entity.UserMangaFollow; import com.magamochi.model.entity.UserMangaFollow;
import com.magamochi.model.repository.*; import com.magamochi.model.repository.*;
import com.magamochi.model.specification.MangaSpecification; import com.magamochi.model.specification.MangaSpecification;
@ -31,7 +31,7 @@ public class MangaService {
private final MangaImportService mangaImportService; private final MangaImportService mangaImportService;
private final UserService userService; private final UserService userService;
private final MangaRepository mangaRepository; private final MangaRepository mangaRepository;
private final MangaProviderRepository mangaProviderRepository; private final MangaContentProviderRepository mangaContentProviderRepository;
private final ContentProviderFactory contentProviderFactory; private final ContentProviderFactory contentProviderFactory;
private final UserFavoriteMangaRepository userFavoriteMangaRepository; private final UserFavoriteMangaRepository userFavoriteMangaRepository;
@ -45,7 +45,7 @@ public class MangaService {
public void fetchAllNotDownloadedChapters(Long mangaProviderId) { public void fetchAllNotDownloadedChapters(Long mangaProviderId) {
var mangaProvider = var mangaProvider =
mangaProviderRepository mangaContentProviderRepository
.findById(mangaProviderId) .findById(mangaProviderId)
.orElseThrow( .orElseThrow(
() -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId)); () -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId));
@ -118,19 +118,19 @@ public class MangaService {
public void fetchFollowedMangaChapters(Long mangaProviderId) { public void fetchFollowedMangaChapters(Long mangaProviderId) {
var mangaProvider = var mangaProvider =
mangaProviderRepository mangaContentProviderRepository
.findById(mangaProviderId) .findById(mangaProviderId)
.orElseThrow( .orElseThrow(
() -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId)); () -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId));
var currentAvailableChapterCount = var currentAvailableChapterCount =
mangaChapterRepository.findByMangaProviderId(mangaProviderId).size(); mangaChapterRepository.findByMangaContentProviderId(mangaProviderId).size();
fetchMangaChapters(mangaProviderId); fetchMangaChapters(mangaProviderId);
mangaChapterRepository.flush(); mangaChapterRepository.flush();
var availableChapterCount = var availableChapterCount =
mangaChapterRepository.findByMangaProviderId(mangaProviderId).size(); mangaChapterRepository.findByMangaContentProviderId(mangaProviderId).size();
if (availableChapterCount <= currentAvailableChapterCount) { if (availableChapterCount <= currentAvailableChapterCount) {
return; return;
@ -145,14 +145,14 @@ public class MangaService {
new NtfyClient.Request( new NtfyClient.Request(
"mangamochi-" + umf.getUser().getId().toString(), "mangamochi-" + umf.getUser().getId().toString(),
umf.getManga().getTitle(), umf.getManga().getTitle(),
"New chapter available on " + mangaProvider.getProvider().getName()))); "New chapter available on " + mangaProvider.getContentProvider().getName())));
} }
public void fetchMangaChapters(Long mangaProviderId) { public void fetchMangaChapters(Long mangaProviderId) {
var mangaProvider = getMangaProviderThrowIfNotFound(mangaProviderId); var mangaProvider = getMangaProviderThrowIfNotFound(mangaProviderId);
var contentProvider = var contentProvider =
contentProviderFactory.getContentProvider(mangaProvider.getProvider().getName()); contentProviderFactory.getContentProvider(mangaProvider.getContentProvider().getName());
var availableChapters = contentProvider.getAvailableChapters(mangaProvider); var availableChapters = contentProvider.getAvailableChapters(mangaProvider);
availableChapters.forEach( availableChapters.forEach(
@ -165,8 +165,8 @@ public class MangaService {
.orElseThrow(() -> new NotFoundException("Manga not found for ID: " + mangaId)); .orElseThrow(() -> new NotFoundException("Manga not found for ID: " + mangaId));
} }
private MangaProvider getMangaProviderThrowIfNotFound(Long mangaProviderId) { private MangaContentProvider getMangaProviderThrowIfNotFound(Long mangaProviderId) {
return mangaProviderRepository return mangaContentProviderRepository
.findById(mangaProviderId) .findById(mangaProviderId)
.orElseThrow( .orElseThrow(
() -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId)); () -> new NotFoundException("Manga Provider not found for ID: " + mangaProviderId));

View File

@ -4,13 +4,12 @@ import static java.util.Objects.isNull;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import com.magamochi.common.exception.NotFoundException; import com.magamochi.common.exception.NotFoundException;
import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.ingestion.model.repository.ContentProviderRepository;
import com.magamochi.model.dto.ImportMangaResponseDTO; import com.magamochi.model.dto.ImportMangaResponseDTO;
import com.magamochi.model.dto.ImportRequestDTO; import com.magamochi.model.dto.ImportRequestDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.entity.Provider; import com.magamochi.model.repository.MangaContentProviderRepository;
import com.magamochi.model.enumeration.ProviderStatus;
import com.magamochi.model.repository.MangaProviderRepository;
import com.magamochi.model.repository.ProviderRepository;
import com.magamochi.service.providers.ManualImportContentProviderFactory; import com.magamochi.service.providers.ManualImportContentProviderFactory;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -24,8 +23,8 @@ public class ProviderManualMangaImportService {
private final ManualImportContentProviderFactory contentProviderFactory; private final ManualImportContentProviderFactory contentProviderFactory;
private final ProviderRepository providerRepository; private final ContentProviderRepository contentProviderRepository;
private final MangaProviderRepository mangaProviderRepository; private final MangaContentProviderRepository mangaContentProviderRepository;
public ImportMangaResponseDTO importFromProvider(Long providerId, ImportRequestDTO requestDTO) { public ImportMangaResponseDTO importFromProvider(Long providerId, ImportRequestDTO requestDTO) {
var provider = getProvider(providerId); var provider = getProvider(providerId);
@ -45,13 +44,13 @@ public class ProviderManualMangaImportService {
throw new NotFoundException("Manga could not be found or created for ID: " + requestDTO.id()); throw new NotFoundException("Manga could not be found or created for ID: " + requestDTO.id());
} }
if (!mangaProviderRepository.existsByMangaAndProviderAndUrlIgnoreCase( if (!mangaContentProviderRepository.existsByMangaAndContentProviderAndUrlIgnoreCase(
manga, provider, requestDTO.id())) { manga, provider, requestDTO.id())) {
mangaProviderRepository.save( mangaContentProviderRepository.save(
MangaProvider.builder() MangaContentProvider.builder()
.manga(manga) .manga(manga)
.mangaTitle(title) .mangaTitle(title)
.provider(provider) .contentProvider(provider)
.url(requestDTO.id()) .url(requestDTO.id())
.build()); .build());
} }
@ -59,13 +58,13 @@ public class ProviderManualMangaImportService {
return new ImportMangaResponseDTO(manga.getId()); return new ImportMangaResponseDTO(manga.getId());
} }
public Provider getProvider(Long providerId) { public ContentProvider getProvider(Long providerId) {
var provider = var provider =
providerRepository contentProviderRepository
.findById(providerId) .findById(providerId)
.orElseThrow(() -> new NotFoundException("Provider not found")); .orElseThrow(() -> new NotFoundException("Provider not found"));
if (!provider.getStatus().equals(ProviderStatus.ACTIVE)) { if (!provider.isActive()) {
throw new IllegalStateException("Provider is not active"); throw new IllegalStateException("Provider is not active");
} }

View File

@ -1,42 +1,28 @@
package com.magamochi.service; package com.magamochi.service;
import static java.util.Objects.nonNull; import com.magamochi.ingestion.model.entity.ContentProvider;
import com.magamochi.ingestion.model.repository.ContentProviderRepository;
import com.magamochi.model.dto.ProviderListDTO;
import com.magamochi.model.entity.Provider;
import com.magamochi.model.enumeration.ProviderStatus;
import com.magamochi.model.repository.ProviderRepository;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class ProviderService { public class ProviderService {
private final ProviderRepository providerRepository; private final ContentProviderRepository contentProviderRepository;
public ProviderListDTO getProviders(Boolean manualImport) { public ContentProvider getOrCreateProvider(String providerName) {
var providers = providerRepository.findAll();
if (nonNull(manualImport) && manualImport) {
providers = providers.stream().filter(Provider::getManualImport).toList();
}
return ProviderListDTO.from(providers);
}
public Provider getOrCreateProvider(String providerName) {
return getOrCreateProvider(providerName, true); return getOrCreateProvider(providerName, true);
} }
public Provider getOrCreateProvider(String providerName, Boolean supportsChapterFetch) { public ContentProvider getOrCreateProvider(String providerName, Boolean supportsChapterFetch) {
return providerRepository return contentProviderRepository
.findByNameIgnoreCase(providerName) .findByNameIgnoreCase(providerName)
.orElseGet( .orElseGet(
() -> () ->
providerRepository.save( contentProviderRepository.save(
Provider.builder() ContentProvider.builder()
.name(providerName) .name(providerName)
.status(ProviderStatus.ACTIVE) .active(true)
.supportsChapterFetch(supportsChapterFetch) .supportsChapterFetch(supportsChapterFetch)
.build())); .build()));
} }

View File

@ -1,12 +1,12 @@
package com.magamochi.service.providers; package com.magamochi.service.providers;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public interface ContentProvider { public interface ContentProvider {
List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider); List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaContentProvider provider);
Map<Integer, String> getChapterImagesUrls(String chapterUrl); Map<Integer, String> getChapterImagesUrls(String chapterUrl);
} }

View File

@ -3,9 +3,9 @@ package com.magamochi.service.providers.impl;
import static java.util.Objects.isNull; import static java.util.Objects.isNull;
import com.magamochi.common.exception.UnprocessableException; import com.magamochi.common.exception.UnprocessableException;
import com.magamochi.ingestion.service.FlareService;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.service.FlareService;
import com.magamochi.service.providers.ContentProvider; import com.magamochi.service.providers.ContentProvider;
import com.magamochi.service.providers.ContentProviders; import com.magamochi.service.providers.ContentProviders;
import com.magamochi.service.providers.ManualImportContentProvider; import com.magamochi.service.providers.ManualImportContentProvider;
@ -25,7 +25,8 @@ public class BatoProvider implements ContentProvider, ManualImportContentProvide
private final FlareService flareService; private final FlareService flareService;
@Override @Override
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) { public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(
MangaContentProvider provider) {
try { try {
var document = var document =
flareService.getContentAsJsoupDocument(provider.getUrl(), ContentProviders.BATO); flareService.getContentAsJsoupDocument(provider.getUrl(), ContentProviders.BATO);

View File

@ -6,7 +6,7 @@ import com.google.common.util.concurrent.RateLimiter;
import com.magamochi.client.MangaDexClient; import com.magamochi.client.MangaDexClient;
import com.magamochi.common.exception.UnprocessableException; import com.magamochi.common.exception.UnprocessableException;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.service.providers.ContentProvider; import com.magamochi.service.providers.ContentProvider;
import com.magamochi.service.providers.ContentProviders; import com.magamochi.service.providers.ContentProviders;
import com.magamochi.service.providers.ManualImportContentProvider; import com.magamochi.service.providers.ManualImportContentProvider;
@ -26,7 +26,8 @@ public class MangaDexProvider implements ContentProvider, ManualImportContentPro
private final RateLimiter mangaDexRateLimiter; private final RateLimiter mangaDexRateLimiter;
@Override @Override
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) { public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(
MangaContentProvider provider) {
try { try {
mangaDexRateLimiter.acquire(); mangaDexRateLimiter.acquire();
var response = var response =

View File

@ -2,7 +2,7 @@ package com.magamochi.service.providers.impl;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO; import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.enumeration.MangaStatus; import com.magamochi.model.enumeration.MangaStatus;
import com.magamochi.service.providers.ContentProvider; import com.magamochi.service.providers.ContentProvider;
import com.magamochi.service.providers.ContentProviders; import com.magamochi.service.providers.ContentProviders;
@ -29,14 +29,14 @@ public class MangaLivreBlogProvider implements ContentProvider, PagedContentProv
@Override @Override
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters( public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(
MangaProvider mangaProvider) { MangaContentProvider mangaContentProvider) {
log.info( log.info(
"Getting available chapters from {}, manga {}", "Getting available chapters from {}, manga {}",
ContentProviders.MANGA_LIVRE_BLOG, ContentProviders.MANGA_LIVRE_BLOG,
mangaProvider.getManga().getTitle()); mangaContentProvider.getManga().getTitle());
try { try {
var document = Jsoup.connect(mangaProvider.getUrl()).get(); var document = Jsoup.connect(mangaContentProvider.getUrl()).get();
var chapterList = document.getElementsByClass("chapters-list").getFirst(); var chapterList = document.getElementsByClass("chapters-list").getFirst();
var chapterItems = chapterList.getElementsByClass("chapter-item"); var chapterItems = chapterList.getElementsByClass("chapter-item");

View File

@ -2,11 +2,11 @@ package com.magamochi.service.providers.impl;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import com.magamochi.ingestion.service.FlareService;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO; import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.enumeration.MangaStatus; import com.magamochi.model.enumeration.MangaStatus;
import com.magamochi.service.FlareService;
import com.magamochi.service.providers.ContentProvider; import com.magamochi.service.providers.ContentProvider;
import com.magamochi.service.providers.ContentProviders; import com.magamochi.service.providers.ContentProviders;
import com.magamochi.service.providers.PagedContentProvider; import com.magamochi.service.providers.PagedContentProvider;
@ -27,7 +27,8 @@ public class MangaLivreProvider implements ContentProvider, PagedContentProvider
private final FlareService flareService; private final FlareService flareService;
@Override @Override
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) { public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(
MangaContentProvider provider) {
log.info( log.info(
"Getting available chapters from {}, manga {}", "Getting available chapters from {}, manga {}",
ContentProviders.MANGA_LIVRE_TO, ContentProviders.MANGA_LIVRE_TO,

View File

@ -3,11 +3,11 @@ package com.magamochi.service.providers.impl;
import static java.util.Objects.isNull; import static java.util.Objects.isNull;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import com.magamochi.ingestion.service.FlareService;
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO; import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO; import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO;
import com.magamochi.model.entity.MangaProvider; import com.magamochi.model.entity.MangaContentProvider;
import com.magamochi.model.enumeration.MangaStatus; import com.magamochi.model.enumeration.MangaStatus;
import com.magamochi.service.FlareService;
import com.magamochi.service.providers.ContentProvider; import com.magamochi.service.providers.ContentProvider;
import com.magamochi.service.providers.ContentProviders; import com.magamochi.service.providers.ContentProviders;
import com.magamochi.service.providers.PagedContentProvider; import com.magamochi.service.providers.PagedContentProvider;
@ -28,7 +28,8 @@ public class PinkRosaScanProvider implements ContentProvider, PagedContentProvid
private final FlareService flareService; private final FlareService flareService;
@Override @Override
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) { public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(
MangaContentProvider provider) {
log.info( log.info(
"Getting available chapters from {}, manga {}", "Getting available chapters from {}, manga {}",
ContentProviders.PINK_ROSA_SCAN, ContentProviders.PINK_ROSA_SCAN,

View File

@ -2,7 +2,6 @@ package com.magamochi.task;
import com.magamochi.model.dto.UpdateMangaFollowChapterListCommand; import com.magamochi.model.dto.UpdateMangaFollowChapterListCommand;
import com.magamochi.model.entity.Manga; import com.magamochi.model.entity.Manga;
import com.magamochi.model.enumeration.ProviderStatus;
import com.magamochi.model.repository.MangaRepository; import com.magamochi.model.repository.MangaRepository;
import com.magamochi.queue.UpdateMangaFollowChapterListProducer; import com.magamochi.queue.UpdateMangaFollowChapterListProducer;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -43,11 +42,10 @@ public class MangaFollowUpdateTask {
private void updateFollowedManga(Manga manga) { private void updateFollowedManga(Manga manga) {
log.info("Fetching available mangas for followed Manga {}", manga.getTitle()); log.info("Fetching available mangas for followed Manga {}", manga.getTitle());
var mangaProviders = manga.getMangaProviders(); var mangaProviders = manga.getMangaContentProviders();
mangaProviders.stream() mangaProviders.stream()
.filter( .filter(mangaProvider -> mangaProvider.getContentProvider().isActive())
mangaProvider -> mangaProvider.getProvider().getStatus().equals(ProviderStatus.ACTIVE))
.forEach( .forEach(
mangaProvider -> mangaProvider ->
producer.sendUpdateMangaFollowChapterListCommand( producer.sendUpdateMangaFollowChapterListCommand(

View File

@ -1,8 +1,8 @@
package com.magamochi.task; package com.magamochi.task;
import com.magamochi.common.exception.NotFoundException; import com.magamochi.common.exception.NotFoundException;
import com.magamochi.ingestion.model.repository.ContentProviderRepository;
import com.magamochi.model.dto.MangaListUpdateCommand; import com.magamochi.model.dto.MangaListUpdateCommand;
import com.magamochi.model.repository.ProviderRepository;
import com.magamochi.queue.UpdateMangaListProducer; import com.magamochi.queue.UpdateMangaListProducer;
import com.magamochi.service.providers.PagedContentProvider; import com.magamochi.service.providers.PagedContentProvider;
import com.magamochi.service.providers.PagedContentProviderFactory; import com.magamochi.service.providers.PagedContentProviderFactory;
@ -22,7 +22,7 @@ public class UpdateMangaListTask {
private final PagedContentProviderFactory contentProviderFactory; private final PagedContentProviderFactory contentProviderFactory;
private final UpdateMangaListProducer updateMangaListProducer; private final UpdateMangaListProducer updateMangaListProducer;
private final ProviderRepository providerRepository; private final ContentProviderRepository contentProviderRepository;
@Scheduled(cron = "${content-providers.cron-expression}") @Scheduled(cron = "${content-providers.cron-expression}")
public void updateMangaListScheduled() { public void updateMangaListScheduled() {
@ -42,7 +42,7 @@ public class UpdateMangaListTask {
public void updateProviderMangaList(Long providerId) { public void updateProviderMangaList(Long providerId) {
var provider = var provider =
providerRepository contentProviderRepository
.findById(providerId) .findById(providerId)
.orElseThrow(() -> new NotFoundException("Provider not found")); .orElseThrow(() -> new NotFoundException("Provider not found"));
var contentProvider = contentProviderFactory.getPagedContentProvider(provider.getName()); var contentProvider = contentProviderFactory.getPagedContentProvider(provider.getName());