refactor(catalog): move classes to new packages
This commit is contained in:
parent
60a4f2cff6
commit
ff6cceb742
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.controller;
|
package com.magamochi.catalog.controller;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.dto.GenreDTO;
|
||||||
|
import com.magamochi.catalog.service.GenreService;
|
||||||
import com.magamochi.model.dto.DefaultResponseDTO;
|
import com.magamochi.model.dto.DefaultResponseDTO;
|
||||||
import com.magamochi.model.dto.GenreDTO;
|
|
||||||
import com.magamochi.service.GenreService;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.dto;
|
package com.magamochi.catalog.model.dto;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Genre;
|
import com.magamochi.catalog.model.entity.Genre;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
@ -1,8 +1,7 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.catalog.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
@ -26,7 +25,4 @@ public class Author {
|
|||||||
@CreationTimestamp private Instant createdAt;
|
@CreationTimestamp private Instant createdAt;
|
||||||
|
|
||||||
@UpdateTimestamp private Instant updatedAt;
|
@UpdateTimestamp private Instant updatedAt;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "author")
|
|
||||||
private List<MangaAuthor> mangaAuthors;
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.catalog.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.util.List;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -19,7 +18,4 @@ public class Genre {
|
|||||||
private Long malId;
|
private Long malId;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "genre")
|
|
||||||
private List<MangaGenre> mangaGenres;
|
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.catalog.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -15,9 +15,7 @@ public class MangaAlternativeTitle {
|
|||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ManyToOne
|
private Long mangaId;
|
||||||
@JoinColumn(name = "manga_id")
|
|
||||||
private Manga manga;
|
|
||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.catalog.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -15,11 +15,7 @@ public class MangaAuthor {
|
|||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ManyToOne
|
private Long mangaId;
|
||||||
@JoinColumn(name = "manga_id")
|
|
||||||
private Manga manga;
|
|
||||||
|
|
||||||
@ManyToOne
|
private Long authorId;
|
||||||
@JoinColumn(name = "author_id")
|
|
||||||
private Author author;
|
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.catalog.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -15,11 +15,7 @@ public class MangaGenre {
|
|||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ManyToOne
|
private Long mangaId;
|
||||||
@JoinColumn(name = "manga_id")
|
|
||||||
private Manga manga;
|
|
||||||
|
|
||||||
@ManyToOne
|
private Long genreId;
|
||||||
@JoinColumn(name = "genre_id")
|
|
||||||
private Genre genre;
|
|
||||||
}
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.catalog.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Author;
|
import com.magamochi.catalog.model.entity.Author;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface AuthorRepository extends JpaRepository<Author, Long> {
|
public interface AuthorRepository extends JpaRepository<Author, Long> {
|
||||||
Optional<Author> findByMalId(Long aLong);
|
Optional<Author> findByMalId(Long malId);
|
||||||
|
|
||||||
Optional<Author> findByName(String name);
|
Optional<Author> findByName(String name);
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.catalog.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Genre;
|
import com.magamochi.catalog.model.entity.Genre;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package com.magamochi.catalog.model.repository;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaAlternativeTitle;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface MangaAlternativeTitlesRepository
|
||||||
|
extends JpaRepository<MangaAlternativeTitle, Long> {
|
||||||
|
List<MangaAlternativeTitle> findAllByMangaId(Long mangaId);
|
||||||
|
|
||||||
|
void deleteAllByMangaId(Long mangaId);
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.magamochi.catalog.model.repository;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaAuthor;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface MangaAuthorRepository extends JpaRepository<MangaAuthor, Long> {
|
||||||
|
void deleteAllByMangaId(Long mangaId);
|
||||||
|
|
||||||
|
Set<MangaAuthor> findAllByMangaId(Long mangaId);
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.magamochi.catalog.model.repository;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaGenre;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface MangaGenreRepository extends JpaRepository<MangaGenre, Long> {
|
||||||
|
void deleteAllByMangaId(Long mangaId);
|
||||||
|
|
||||||
|
List<MangaGenre> findAllByMangaId(Long mangaId);
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.magamochi.catalog.service;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.Author;
|
||||||
|
import com.magamochi.catalog.model.repository.AuthorRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthorService {
|
||||||
|
private final AuthorRepository authorRepository;
|
||||||
|
|
||||||
|
public Long findOrCreateAuthor(Long malAuthorId, String authorName) {
|
||||||
|
return authorRepository
|
||||||
|
.findByName(authorName)
|
||||||
|
.orElseGet(
|
||||||
|
() ->
|
||||||
|
authorRepository.save(Author.builder().malId(malAuthorId).name(authorName).build()))
|
||||||
|
.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAuthorNamesByIds(Set<Long> genreIds) {
|
||||||
|
var genres = authorRepository.findAllById(genreIds);
|
||||||
|
|
||||||
|
return genres.stream().map(Author::getName).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.magamochi.catalog.service;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.dto.GenreDTO;
|
||||||
|
import com.magamochi.catalog.model.entity.Genre;
|
||||||
|
import com.magamochi.catalog.model.repository.GenreRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GenreService {
|
||||||
|
private final GenreRepository genreRepository;
|
||||||
|
|
||||||
|
public Long findOrCreateGenre(Long malGenreId, String genreName) {
|
||||||
|
return genreRepository
|
||||||
|
.findByName(genreName)
|
||||||
|
.orElseGet(
|
||||||
|
() -> genreRepository.save(Genre.builder().malId(malGenreId).name(genreName).build()))
|
||||||
|
.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getGenreNamesByIds(Set<Long> genreIds) {
|
||||||
|
var genres = genreRepository.findAllById(genreIds);
|
||||||
|
|
||||||
|
return genres.stream().map(Genre::getName).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GenreDTO> getGenres() {
|
||||||
|
var genres = genreRepository.findAll();
|
||||||
|
|
||||||
|
return genres.stream().map(GenreDTO::from).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.magamochi.catalog.service;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaAlternativeTitle;
|
||||||
|
import com.magamochi.catalog.model.repository.MangaAlternativeTitlesRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MangaAlternativeTitleService {
|
||||||
|
private final MangaAlternativeTitlesRepository mangaAlternativeTitlesRepository;
|
||||||
|
|
||||||
|
public void saveOrUpdateMangaAlternativeTitles(Long mangaId, List<String> alternativeTitles) {
|
||||||
|
mangaAlternativeTitlesRepository.deleteAllByMangaId(mangaId);
|
||||||
|
|
||||||
|
alternativeTitles.forEach(
|
||||||
|
title ->
|
||||||
|
mangaAlternativeTitlesRepository.save(
|
||||||
|
MangaAlternativeTitle.builder().mangaId(mangaId).title(title).build()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMangaAlternativeTitles(Long mangaId) {
|
||||||
|
return mangaAlternativeTitlesRepository.findAllByMangaId(mangaId).stream()
|
||||||
|
.map(MangaAlternativeTitle::getTitle)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.magamochi.catalog.service;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaAuthor;
|
||||||
|
import com.magamochi.catalog.model.repository.MangaAuthorRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MangaAuthorService {
|
||||||
|
private final AuthorService authorService;
|
||||||
|
private final MangaAuthorRepository mangaAuthorRepository;
|
||||||
|
|
||||||
|
public void saveOrUpdateMangaAuthors(Long mangaId, Set<Long> authorIds) {
|
||||||
|
mangaAuthorRepository.deleteAllByMangaId(mangaId);
|
||||||
|
|
||||||
|
authorIds.forEach(
|
||||||
|
authorId ->
|
||||||
|
mangaAuthorRepository.save(
|
||||||
|
MangaAuthor.builder().mangaId(mangaId).authorId(authorId).build()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMangaAuthors(Long mangaId) {
|
||||||
|
var mangaAuthorIds =
|
||||||
|
mangaAuthorRepository.findAllByMangaId(mangaId).stream()
|
||||||
|
.map(MangaAuthor::getAuthorId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return authorService.getAuthorNamesByIds(mangaAuthorIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.magamochi.catalog.service;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.MangaGenre;
|
||||||
|
import com.magamochi.catalog.model.repository.MangaGenreRepository;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MangaGenreService {
|
||||||
|
private final GenreService genreService;
|
||||||
|
private final MangaGenreRepository mangaGenreRepository;
|
||||||
|
|
||||||
|
public void saveOrUpdateMangaGenres(Long mangaId, Set<Long> genreIds) {
|
||||||
|
mangaGenreRepository.deleteAllByMangaId(mangaId);
|
||||||
|
|
||||||
|
genreIds.forEach(
|
||||||
|
genreId ->
|
||||||
|
mangaGenreRepository.save(
|
||||||
|
MangaGenre.builder().mangaId(mangaId).genreId(genreId).build()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getMangaGenres(Long mangaId) {
|
||||||
|
var mangaGenreIds =
|
||||||
|
mangaGenreRepository.findAllByMangaId(mangaId).stream()
|
||||||
|
.map(MangaGenre::getGenreId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return genreService.getGenreNamesByIds(mangaGenreIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.config;
|
package com.magamochi.content.config;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package com.magamochi.controller;
|
package com.magamochi.content.controller;
|
||||||
|
|
||||||
|
import com.magamochi.content.service.MangaChapterService;
|
||||||
import com.magamochi.model.dto.DefaultResponseDTO;
|
import com.magamochi.model.dto.DefaultResponseDTO;
|
||||||
import com.magamochi.model.dto.MangaChapterImagesDTO;
|
import com.magamochi.content.model.dto.MangaChapterImagesDTO;
|
||||||
import com.magamochi.model.enumeration.ArchiveFileType;
|
import com.magamochi.model.enumeration.ArchiveFileType;
|
||||||
import com.magamochi.service.MangaChapterService;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.model.dto;
|
package com.magamochi.content.model.dto;
|
||||||
|
|
||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Language;
|
import com.magamochi.content.model.entity.Language;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.magamochi.model.dto;
|
package com.magamochi.content.model.dto;
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
import com.magamochi.content.model.entity.Language;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
@ -10,12 +11,12 @@ public record MangaChapterDTO(
|
|||||||
@NotNull Boolean downloaded,
|
@NotNull Boolean downloaded,
|
||||||
@NotNull Boolean isRead,
|
@NotNull Boolean isRead,
|
||||||
LanguageDTO language) {
|
LanguageDTO language) {
|
||||||
public static MangaChapterDTO from(MangaChapter mangaChapter) {
|
public static MangaChapterDTO from(MangaChapter mangaChapter, Language language) {
|
||||||
return new MangaChapterDTO(
|
return new MangaChapterDTO(
|
||||||
mangaChapter.getId(),
|
mangaChapter.getId(),
|
||||||
mangaChapter.getTitle(),
|
mangaChapter.getTitle(),
|
||||||
mangaChapter.getDownloaded(),
|
mangaChapter.getDownloaded(),
|
||||||
mangaChapter.getRead(),
|
mangaChapter.getRead(),
|
||||||
LanguageDTO.from(mangaChapter.getLanguage()));
|
LanguageDTO.from(language));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.magamochi.content.model.dto;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record MangaChapterImagesDTO(
|
||||||
|
@NotNull Long id,
|
||||||
|
@NotBlank String mangaTitle,
|
||||||
|
Long previousChapterId,
|
||||||
|
Long nextChapterId,
|
||||||
|
@NotNull List<@NotBlank String> chapterImageKeys) {
|
||||||
|
public static MangaChapterImagesDTO from(
|
||||||
|
MangaChapter mangaChapter, Long prevId, Long nextId, List<String> chapterImageKeys) {
|
||||||
|
return new MangaChapterImagesDTO(
|
||||||
|
mangaChapter.getId(), mangaChapter.getTitle(), prevId, nextId, chapterImageKeys);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.content.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.content.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.content.model.entity;
|
||||||
|
|
||||||
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
@ -35,12 +35,7 @@ public class MangaChapter {
|
|||||||
|
|
||||||
@UpdateTimestamp private Instant updatedAt;
|
@UpdateTimestamp private Instant updatedAt;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "mangaChapter")
|
|
||||||
private List<MangaChapterImage> mangaChapterImages;
|
|
||||||
|
|
||||||
private Integer chapterNumber;
|
private Integer chapterNumber;
|
||||||
|
|
||||||
@ManyToOne
|
private Long languageId;
|
||||||
@JoinColumn(name = "language_id")
|
|
||||||
private Language language;
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.content.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
@ -18,13 +19,9 @@ public class MangaChapterImage {
|
|||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ManyToOne
|
private Long mangaChapterId;
|
||||||
@JoinColumn(name = "manga_chapter_id")
|
|
||||||
private MangaChapter mangaChapter;
|
|
||||||
|
|
||||||
@OneToOne
|
private UUID imageId;
|
||||||
@JoinColumn(name = "image_id")
|
|
||||||
private Image image;
|
|
||||||
|
|
||||||
private int position;
|
private int position;
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.content.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Image;
|
import com.magamochi.content.model.entity.Image;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.content.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Language;
|
import com.magamochi.content.model.entity.Language;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.magamochi.content.model.repository;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.MangaChapterImage;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface MangaChapterImageRepository extends JpaRepository<MangaChapterImage, Long> {
|
||||||
|
List<MangaChapterImage> findAllByMangaChapterId(Long mangaChapterId);
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.content.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
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;
|
||||||
@ -1,8 +1,13 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.content.service;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.Image;
|
||||||
|
import com.magamochi.content.model.repository.ImageRepository;
|
||||||
|
import com.magamochi.exception.NotFoundException;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Image;
|
|
||||||
import com.magamochi.model.repository.ImageRepository;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -14,6 +19,10 @@ public class ImageService {
|
|||||||
private final S3Service s3Service;
|
private final S3Service s3Service;
|
||||||
private final ImageRepository imageRepository;
|
private final ImageRepository imageRepository;
|
||||||
|
|
||||||
|
public List<String> getImageFileKeys(Set<UUID> imageIds) {
|
||||||
|
return imageRepository.findAllById(imageIds).stream().map(Image::getFileKey).toList();
|
||||||
|
}
|
||||||
|
|
||||||
public Image uploadImage(byte[] data, String contentType, String path) {
|
public Image uploadImage(byte[] data, String contentType, String path) {
|
||||||
log.info("Uploading image {} to S3", path);
|
log.info("Uploading image {} to S3", path);
|
||||||
var fileKey = s3Service.uploadFile(data, contentType, path);
|
var fileKey = s3Service.uploadFile(data, contentType, path);
|
||||||
@ -21,7 +30,12 @@ public class ImageService {
|
|||||||
return imageRepository.save(Image.builder().fileKey(fileKey).build());
|
return imageRepository.save(Image.builder().fileKey(fileKey).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream getImageStream(Image image) {
|
public InputStream getImageStream(UUID imageId) {
|
||||||
|
var image =
|
||||||
|
imageRepository
|
||||||
|
.findById(imageId)
|
||||||
|
.orElseThrow(() -> new NotFoundException("Image not found"));
|
||||||
|
|
||||||
return s3Service.getFile(image.getFileKey());
|
return s3Service.getFile(image.getFileKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.magamochi.content.service;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.Language;
|
||||||
|
import com.magamochi.content.model.repository.LanguageRepository;
|
||||||
|
import com.magamochi.exception.NotFoundException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LanguageService {
|
||||||
|
public final LanguageRepository languageRepository;
|
||||||
|
|
||||||
|
public Long getLanguageIdOrThrow(String code) {
|
||||||
|
return languageRepository
|
||||||
|
.findByCodeIgnoreCase(code)
|
||||||
|
.orElseThrow(() -> new NotFoundException("Language with code " + code + " not found"))
|
||||||
|
.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Language getLanguageOrThrow(Long languageId) {
|
||||||
|
return languageRepository
|
||||||
|
.findById(languageId)
|
||||||
|
.orElseThrow(() -> new NotFoundException("Language not found"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.magamochi.content.service;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.MangaChapterImage;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterImageRepository;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MangaChapterImageService {
|
||||||
|
private final ImageService imageService;
|
||||||
|
private final MangaChapterImageRepository mangaChapterImageRepository;
|
||||||
|
|
||||||
|
public List<String> getMangaChapterImageKeys(Long mangaChapterId) {
|
||||||
|
var mangaChapterImageIds =
|
||||||
|
mangaChapterImageRepository.findAllByMangaChapterId(mangaChapterId).stream()
|
||||||
|
.sorted(Comparator.comparing(MangaChapterImage::getPosition))
|
||||||
|
.map(MangaChapterImage::getImageId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return imageService.getImageFileKeys(mangaChapterImageIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.content.service;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.RateLimiter;
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapterImage;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterImageRepository;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterRepository;
|
||||||
import com.magamochi.exception.UnprocessableException;
|
import com.magamochi.exception.UnprocessableException;
|
||||||
import com.magamochi.model.dto.MangaChapterArchiveDTO;
|
import com.magamochi.model.dto.MangaChapterArchiveDTO;
|
||||||
import com.magamochi.model.dto.MangaChapterImagesDTO;
|
import com.magamochi.content.model.dto.MangaChapterImagesDTO;
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
|
||||||
import com.magamochi.model.entity.MangaChapterImage;
|
|
||||||
import com.magamochi.model.enumeration.ArchiveFileType;
|
import com.magamochi.model.enumeration.ArchiveFileType;
|
||||||
import com.magamochi.model.repository.MangaChapterImageRepository;
|
import com.magamochi.ingestion.service.providers.ContentProviderFactory;
|
||||||
import com.magamochi.model.repository.MangaChapterRepository;
|
|
||||||
import com.magamochi.service.providers.ContentProviderFactory;
|
|
||||||
import io.github.resilience4j.retry.Retry;
|
import io.github.resilience4j.retry.Retry;
|
||||||
import io.github.resilience4j.retry.RetryRegistry;
|
import io.github.resilience4j.retry.RetryRegistry;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
@ -36,6 +36,7 @@ public class MangaChapterService {
|
|||||||
private final MangaChapterImageRepository mangaChapterImageRepository;
|
private final MangaChapterImageRepository mangaChapterImageRepository;
|
||||||
|
|
||||||
private final ImageService imageService;
|
private final ImageService imageService;
|
||||||
|
private final MangaChapterImageService mangaChapterImageService;
|
||||||
|
|
||||||
private final ContentProviderFactory contentProviderFactory;
|
private final ContentProviderFactory contentProviderFactory;
|
||||||
|
|
||||||
@ -104,9 +105,9 @@ public class MangaChapterService {
|
|||||||
entry.getValue());
|
entry.getValue());
|
||||||
|
|
||||||
return MangaChapterImage.builder()
|
return MangaChapterImage.builder()
|
||||||
.mangaChapter(chapter)
|
.mangaChapterId(chapter.getId())
|
||||||
.position(entry.getKey())
|
.position(entry.getKey())
|
||||||
.image(image)
|
.imageId(image.getId())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -148,7 +149,9 @@ public class MangaChapterService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MangaChapterImagesDTO.from(chapter, prevId, nextId);
|
var imageFileKeys = mangaChapterImageService.getMangaChapterImageKeys(chapter.getId());
|
||||||
|
|
||||||
|
return MangaChapterImagesDTO.from(chapter, prevId, nextId, imageFileKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsRead(Long chapterId) {
|
public void markAsRead(Long chapterId) {
|
||||||
@ -162,7 +165,7 @@ public class MangaChapterService {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
var chapter = getMangaChapterThrowIfNotFound(chapterId);
|
var chapter = getMangaChapterThrowIfNotFound(chapterId);
|
||||||
|
|
||||||
var chapterImages = mangaChapterImageRepository.findAllByMangaChapter(chapter);
|
var chapterImages = mangaChapterImageRepository.findAllByMangaChapterId(chapter.getId());
|
||||||
|
|
||||||
var byteArrayOutputStream =
|
var byteArrayOutputStream =
|
||||||
switch (archiveFileType) {
|
switch (archiveFileType) {
|
||||||
@ -191,7 +194,7 @@ public class MangaChapterService {
|
|||||||
var paddedFileName = String.format("%0" + paddingLength + "d.jpg", imgSrc.getPosition());
|
var paddedFileName = String.format("%0" + paddingLength + "d.jpg", imgSrc.getPosition());
|
||||||
|
|
||||||
zipOutputStream.putNextEntry(new ZipEntry(paddedFileName));
|
zipOutputStream.putNextEntry(new ZipEntry(paddedFileName));
|
||||||
IOUtils.copy(imageService.getImageStream(imgSrc.getImage()), zipOutputStream);
|
IOUtils.copy(imageService.getImageStream(imgSrc.getImageId()), zipOutputStream);
|
||||||
zipOutputStream.closeEntry();
|
zipOutputStream.closeEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.content.service;
|
||||||
|
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.task;
|
package com.magamochi.content.task;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Image;
|
import com.magamochi.content.model.entity.Image;
|
||||||
import com.magamochi.model.repository.ImageRepository;
|
import com.magamochi.content.model.repository.ImageRepository;
|
||||||
import com.magamochi.service.S3Service;
|
import com.magamochi.content.service.S3Service;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
@ -4,7 +4,7 @@ import com.magamochi.client.NtfyClient;
|
|||||||
import com.magamochi.model.dto.DefaultResponseDTO;
|
import com.magamochi.model.dto.DefaultResponseDTO;
|
||||||
import com.magamochi.model.dto.UpdateMangaDataCommand;
|
import com.magamochi.model.dto.UpdateMangaDataCommand;
|
||||||
import com.magamochi.queue.UpdateMangaDataProducer;
|
import com.magamochi.queue.UpdateMangaDataProducer;
|
||||||
import com.magamochi.task.ImageCleanupTask;
|
import com.magamochi.content.task.ImageCleanupTask;
|
||||||
import com.magamochi.task.MangaFollowUpdateTask;
|
import com.magamochi.task.MangaFollowUpdateTask;
|
||||||
import com.magamochi.task.UpdateMangaListTask;
|
import com.magamochi.task.UpdateMangaListTask;
|
||||||
import com.magamochi.user.model.repository.UserRepository;
|
import com.magamochi.user.model.repository.UserRepository;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.magamochi.controller;
|
package com.magamochi.controller;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.dto.MangaChapterDTO;
|
||||||
import com.magamochi.model.dto.*;
|
import com.magamochi.model.dto.*;
|
||||||
import com.magamochi.service.MangaService;
|
import com.magamochi.service.MangaService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package com.magamochi.controller;
|
|||||||
|
|
||||||
import com.magamochi.model.dto.DefaultResponseDTO;
|
import com.magamochi.model.dto.DefaultResponseDTO;
|
||||||
import com.magamochi.model.dto.ImportReviewDTO;
|
import com.magamochi.model.dto.ImportReviewDTO;
|
||||||
import com.magamochi.service.MangaImportReviewService;
|
import com.magamochi.ingestion.service.MangaImportReviewService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.controller;
|
package com.magamochi.ingestion.controller;
|
||||||
|
|
||||||
import com.magamochi.model.dto.DefaultResponseDTO;
|
import com.magamochi.model.dto.DefaultResponseDTO;
|
||||||
import com.magamochi.model.dto.ProviderListDTO;
|
import com.magamochi.ingestion.model.dto.ProviderListDTO;
|
||||||
import com.magamochi.service.ProviderService;
|
import com.magamochi.ingestion.service.ProviderService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -19,7 +19,7 @@ public class ProviderController {
|
|||||||
tags = {"Provider"},
|
tags = {"Provider"},
|
||||||
operationId = "getProviders")
|
operationId = "getProviders")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public DefaultResponseDTO<ProviderListDTO> getMangas(
|
public DefaultResponseDTO<ProviderListDTO> getProviders(
|
||||||
@RequestParam(name = "manualImport", required = false) Boolean manualImport) {
|
@RequestParam(name = "manualImport", required = false) Boolean manualImport) {
|
||||||
return DefaultResponseDTO.ok(providerService.getProviders(manualImport));
|
return DefaultResponseDTO.ok(providerService.getProviders(manualImport));
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.dto;
|
package com.magamochi.ingestion.model.dto;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.magamochi.ingestion.model.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
public record TitleMatchRequestDTO(
|
||||||
|
String title, List<String> options,
|
||||||
|
Integer threshold) {
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.magamochi.ingestion.model.dto;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
public record TitleMatchResponseDTO(
|
||||||
|
boolean matchFound,
|
||||||
|
String bestMatch,
|
||||||
|
Double similarity) {
|
||||||
|
}
|
||||||
@ -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;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.ingestion.model.entity;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.ingestion.model.entity;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
|
import com.magamochi.model.entity.Manga;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.ingestion.model.entity;
|
||||||
|
|
||||||
import com.magamochi.model.enumeration.ProviderStatus;
|
import com.magamochi.ingestion.model.enumeration.ProviderStatus;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.model.enumeration;
|
package com.magamochi.ingestion.model.enumeration;
|
||||||
|
|
||||||
public enum ProviderStatus {
|
public enum ProviderStatus {
|
||||||
ACTIVE,
|
ACTIVE,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.ingestion.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaImportReview;
|
import com.magamochi.ingestion.model.entity.MangaImportReview;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface MangaImportReviewRepository extends JpaRepository<MangaImportReview, Long> {
|
public interface MangaImportReviewRepository extends JpaRepository<MangaImportReview, Long> {
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.ingestion.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Manga;
|
import com.magamochi.model.entity.Manga;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.repository;
|
package com.magamochi.ingestion.model.repository;
|
||||||
|
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
@ -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;
|
||||||
@ -1,11 +1,11 @@
|
|||||||
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 java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.registry;
|
package com.magamochi.ingestion.service;
|
||||||
|
|
||||||
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;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.ingestion.service;
|
||||||
|
|
||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
@ -8,10 +8,10 @@ import com.magamochi.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.MangaImportReview;
|
import com.magamochi.ingestion.model.entity.MangaImportReview;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.repository.MangaImportReviewRepository;
|
import com.magamochi.ingestion.model.repository.MangaImportReviewRepository;
|
||||||
import com.magamochi.model.repository.MangaProviderRepository;
|
import com.magamochi.ingestion.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;
|
||||||
@ -1,11 +1,11 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.ingestion.service;
|
||||||
|
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
import com.magamochi.model.dto.ProviderListDTO;
|
import com.magamochi.ingestion.model.dto.ProviderListDTO;
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import com.magamochi.model.enumeration.ProviderStatus;
|
import com.magamochi.ingestion.model.enumeration.ProviderStatus;
|
||||||
import com.magamochi.model.repository.ProviderRepository;
|
import com.magamochi.ingestion.model.repository.ProviderRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -1,10 +1,11 @@
|
|||||||
package com.magamochi.service;
|
package com.magamochi.ingestion.service;
|
||||||
|
|
||||||
|
import static java.util.Objects.isNull;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||||
|
|
||||||
import com.magamochi.model.dto.TitleMatchRequestDTO;
|
import com.magamochi.ingestion.model.dto.TitleMatchRequestDTO;
|
||||||
import com.magamochi.model.dto.TitleMatchResponseDTO;
|
import com.magamochi.ingestion.model.dto.TitleMatchResponseDTO;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.apache.commons.text.similarity.LevenshteinDistance;
|
import org.apache.commons.text.similarity.LevenshteinDistance;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -15,17 +16,23 @@ public class TitleMatcherService {
|
|||||||
private final LevenshteinDistance levenshteinDistance = LevenshteinDistance.getDefaultInstance();
|
private final LevenshteinDistance levenshteinDistance = LevenshteinDistance.getDefaultInstance();
|
||||||
|
|
||||||
public TitleMatchResponseDTO findBestMatch(TitleMatchRequestDTO request) {
|
public TitleMatchResponseDTO findBestMatch(TitleMatchRequestDTO request) {
|
||||||
if (isBlank(request.getTitle()) || isEmpty(request.getOptions())) {
|
if (isBlank(request.title()) || isEmpty(request.options())) {
|
||||||
throw new IllegalArgumentException("Title and options are required");
|
throw new IllegalArgumentException("Title and options are required");
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Finding best match for {}. Options: {}", request.getTitle(), request.getOptions());
|
// Set the default threshold if not specified
|
||||||
|
var threshold = request.threshold();
|
||||||
|
if (isNull(threshold) || threshold == 0) {
|
||||||
|
threshold = 85;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Finding best match for {}. Options: {}", request.title(), request.options());
|
||||||
|
|
||||||
String bestMatch = null;
|
String bestMatch = null;
|
||||||
double bestScore = 0.0;
|
double bestScore = 0.0;
|
||||||
|
|
||||||
for (var option : request.getOptions()) {
|
for (var option : request.options()) {
|
||||||
var score = calculateSimilarityScore(request.getTitle(), option);
|
var score = calculateSimilarityScore(request.title(), option);
|
||||||
|
|
||||||
if (score > bestScore) {
|
if (score > bestScore) {
|
||||||
bestScore = score;
|
bestScore = score;
|
||||||
@ -33,9 +40,9 @@ public class TitleMatcherService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestScore >= request.getThreshold()) {
|
if (bestScore >= threshold) {
|
||||||
log.info(
|
log.info(
|
||||||
"Found best match for {}: {}. Similarity: {}", request.getTitle(), bestMatch, bestScore);
|
"Found best match for {}: {}. Similarity: {}", request.title(), bestMatch, bestScore);
|
||||||
|
|
||||||
return TitleMatchResponseDTO.builder()
|
return TitleMatchResponseDTO.builder()
|
||||||
.matchFound(true)
|
.matchFound(true)
|
||||||
@ -44,7 +51,7 @@ public class TitleMatcherService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("No match found for {}. Threshold: {}", request.getTitle(), request.getThreshold());
|
log.info("No match found for {}. Threshold: {}", request.title(), threshold);
|
||||||
|
|
||||||
return TitleMatchResponseDTO.builder().matchFound(false).build();
|
return TitleMatchResponseDTO.builder().matchFound(false).build();
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
public class ContentProviders {
|
public class ContentProviders {
|
||||||
public static final String MANGA_LIVRE_TO = "Manga Livre.to";
|
public static final String MANGA_LIVRE_TO = "Manga Livre.to";
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
public interface ManualImportContentProvider {
|
public interface ManualImportContentProvider {
|
||||||
String getMangaTitle(String value);
|
String getMangaTitle(String value);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO;
|
import com.magamochi.model.dto.ContentProviderMangaInfoResponseDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers;
|
package com.magamochi.ingestion.service.providers;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -1,14 +1,14 @@
|
|||||||
package com.magamochi.service.providers.impl;
|
package com.magamochi.ingestion.service.providers.impl;
|
||||||
|
|
||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
import com.magamochi.exception.UnprocessableException;
|
import com.magamochi.exception.UnprocessableException;
|
||||||
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.service.FlareService;
|
import com.magamochi.ingestion.service.FlareService;
|
||||||
import com.magamochi.service.providers.ContentProvider;
|
import com.magamochi.ingestion.service.providers.ContentProvider;
|
||||||
import com.magamochi.service.providers.ContentProviders;
|
import com.magamochi.ingestion.service.providers.ContentProviders;
|
||||||
import com.magamochi.service.providers.ManualImportContentProvider;
|
import com.magamochi.ingestion.service.providers.ManualImportContentProvider;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.magamochi.service.providers.impl;
|
package com.magamochi.ingestion.service.providers.impl;
|
||||||
|
|
||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
@ -6,10 +6,10 @@ import com.google.common.util.concurrent.RateLimiter;
|
|||||||
import com.magamochi.client.MangaDexClient;
|
import com.magamochi.client.MangaDexClient;
|
||||||
import com.magamochi.exception.UnprocessableException;
|
import com.magamochi.exception.UnprocessableException;
|
||||||
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.service.providers.ContentProvider;
|
import com.magamochi.ingestion.service.providers.ContentProvider;
|
||||||
import com.magamochi.service.providers.ContentProviders;
|
import com.magamochi.ingestion.service.providers.ContentProviders;
|
||||||
import com.magamochi.service.providers.ManualImportContentProvider;
|
import com.magamochi.ingestion.service.providers.ManualImportContentProvider;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -1,12 +1,12 @@
|
|||||||
package com.magamochi.service.providers.impl;
|
package com.magamochi.ingestion.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.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.enumeration.MangaStatus;
|
import com.magamochi.model.enumeration.MangaStatus;
|
||||||
import com.magamochi.service.providers.ContentProvider;
|
import com.magamochi.ingestion.service.providers.ContentProvider;
|
||||||
import com.magamochi.service.providers.ContentProviders;
|
import com.magamochi.ingestion.service.providers.ContentProviders;
|
||||||
import com.magamochi.service.providers.PagedContentProvider;
|
import com.magamochi.ingestion.service.providers.PagedContentProvider;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -1,15 +1,15 @@
|
|||||||
package com.magamochi.service.providers.impl;
|
package com.magamochi.ingestion.service.providers.impl;
|
||||||
|
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
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.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.enumeration.MangaStatus;
|
import com.magamochi.model.enumeration.MangaStatus;
|
||||||
import com.magamochi.service.FlareService;
|
import com.magamochi.ingestion.service.FlareService;
|
||||||
import com.magamochi.service.providers.ContentProvider;
|
import com.magamochi.ingestion.service.providers.ContentProvider;
|
||||||
import com.magamochi.service.providers.ContentProviders;
|
import com.magamochi.ingestion.service.providers.ContentProviders;
|
||||||
import com.magamochi.service.providers.PagedContentProvider;
|
import com.magamochi.ingestion.service.providers.PagedContentProvider;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -1,16 +1,16 @@
|
|||||||
package com.magamochi.service.providers.impl;
|
package com.magamochi.ingestion.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.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.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.enumeration.MangaStatus;
|
import com.magamochi.model.enumeration.MangaStatus;
|
||||||
import com.magamochi.service.FlareService;
|
import com.magamochi.ingestion.service.FlareService;
|
||||||
import com.magamochi.service.providers.ContentProvider;
|
import com.magamochi.ingestion.service.providers.ContentProvider;
|
||||||
import com.magamochi.service.providers.ContentProviders;
|
import com.magamochi.ingestion.service.providers.ContentProviders;
|
||||||
import com.magamochi.service.providers.PagedContentProvider;
|
import com.magamochi.ingestion.service.providers.PagedContentProvider;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -1,7 +1,7 @@
|
|||||||
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.ingestion.service.FlareSessionRegistry;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -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;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.magamochi.model.dto;
|
package com.magamochi.model.dto;
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaImportReview;
|
import com.magamochi.ingestion.model.entity.MangaImportReview;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
package com.magamochi.model.dto;
|
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
|
||||||
import com.magamochi.model.entity.MangaChapterImage;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public record MangaChapterImagesDTO(
|
|
||||||
@NotNull Long id,
|
|
||||||
@NotBlank String mangaTitle,
|
|
||||||
Long previousChapterId,
|
|
||||||
Long nextChapterId,
|
|
||||||
@NotNull List<@NotBlank String> chapterImageKeys) {
|
|
||||||
public static MangaChapterImagesDTO from(MangaChapter mangaChapter, Long prevId, Long nextId) {
|
|
||||||
return new MangaChapterImagesDTO(
|
|
||||||
mangaChapter.getId(),
|
|
||||||
mangaChapter.getTitle(),
|
|
||||||
prevId,
|
|
||||||
nextId,
|
|
||||||
mangaChapter.getMangaChapterImages().stream()
|
|
||||||
.sorted(Comparator.comparing(MangaChapterImage::getPosition))
|
|
||||||
.map(mangaChapterImage -> mangaChapterImage.getImage().getFileKey())
|
|
||||||
.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
package com.magamochi.model.dto;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record MangaChapterResponseDTO(
|
|
||||||
@NotNull UUID id,
|
|
||||||
// @NotNull Long mangaProviderId,
|
|
||||||
@NotNull String chapterTitle,
|
|
||||||
@NotNull String chapterUrl) {}
|
|
||||||
@ -2,11 +2,10 @@ package com.magamochi.model.dto;
|
|||||||
|
|
||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
import com.magamochi.model.entity.Manga;
|
import com.magamochi.model.entity.Manga;
|
||||||
import com.magamochi.model.entity.MangaAlternativeTitle;
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
import com.magamochi.ingestion.model.enumeration.ProviderStatus;
|
||||||
import com.magamochi.model.entity.MangaProvider;
|
|
||||||
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;
|
||||||
@ -29,7 +28,13 @@ public record MangaDTO(
|
|||||||
@NotNull Integer chapterCount,
|
@NotNull Integer chapterCount,
|
||||||
@NotNull Boolean favorite,
|
@NotNull Boolean favorite,
|
||||||
@NotNull Boolean following) {
|
@NotNull Boolean following) {
|
||||||
public static MangaDTO from(Manga manga, Boolean favorite, Boolean following) {
|
public static MangaDTO from(
|
||||||
|
Manga manga,
|
||||||
|
Boolean favorite,
|
||||||
|
Boolean following,
|
||||||
|
List<String> genres,
|
||||||
|
List<String> authors,
|
||||||
|
List<String> alternativeTitles) {
|
||||||
return new MangaDTO(
|
return new MangaDTO(
|
||||||
manga.getId(),
|
manga.getId(),
|
||||||
manga.getTitle(),
|
manga.getTitle(),
|
||||||
@ -39,11 +44,9 @@ public record MangaDTO(
|
|||||||
manga.getPublishedTo(),
|
manga.getPublishedTo(),
|
||||||
manga.getSynopsis(),
|
manga.getSynopsis(),
|
||||||
manga.getMangaProviders().size(),
|
manga.getMangaProviders().size(),
|
||||||
manga.getAlternativeTitles().stream().map(MangaAlternativeTitle::getTitle).toList(),
|
alternativeTitles,
|
||||||
manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(),
|
genres,
|
||||||
manga.getMangaAuthors().stream()
|
authors,
|
||||||
.map(mangaAuthor -> mangaAuthor.getAuthor().getName())
|
|
||||||
.toList(),
|
|
||||||
manga.getScore(),
|
manga.getScore(),
|
||||||
manga.getMangaProviders().stream().map(MangaProviderDTO::from).toList(),
|
manga.getMangaProviders().stream().map(MangaProviderDTO::from).toList(),
|
||||||
manga.getChapterCount(),
|
manga.getChapterCount(),
|
||||||
|
|||||||
@ -20,7 +20,8 @@ public record MangaListDTO(
|
|||||||
@NotNull List<String> authors,
|
@NotNull List<String> authors,
|
||||||
@NotNull Double score,
|
@NotNull Double score,
|
||||||
@NotNull Boolean favorite) {
|
@NotNull Boolean favorite) {
|
||||||
public static MangaListDTO from(Manga manga, boolean favorite) {
|
public static MangaListDTO from(
|
||||||
|
Manga manga, boolean favorite, List<String> genres, List<String> authors) {
|
||||||
return new MangaListDTO(
|
return new MangaListDTO(
|
||||||
manga.getId(),
|
manga.getId(),
|
||||||
manga.getTitle(),
|
manga.getTitle(),
|
||||||
@ -29,10 +30,8 @@ public record MangaListDTO(
|
|||||||
manga.getPublishedFrom(),
|
manga.getPublishedFrom(),
|
||||||
manga.getPublishedTo(),
|
manga.getPublishedTo(),
|
||||||
manga.getMangaProviders().size(),
|
manga.getMangaProviders().size(),
|
||||||
manga.getMangaGenres().stream().map(mangaGenre -> mangaGenre.getGenre().getName()).toList(),
|
genres,
|
||||||
manga.getMangaAuthors().stream()
|
authors,
|
||||||
.map(mangaAuthor -> mangaAuthor.getAuthor().getName())
|
|
||||||
.toList(),
|
|
||||||
manga.getScore(),
|
manga.getScore(),
|
||||||
favorite);
|
favorite);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
package com.magamochi.model.dto;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Builder
|
|
||||||
public class TitleMatchRequestDTO {
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
private List<String> options;
|
|
||||||
|
|
||||||
@Builder.Default private int threshold = 85;
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package com.magamochi.model.dto;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Builder
|
|
||||||
public class TitleMatchResponseDTO {
|
|
||||||
boolean matchFound;
|
|
||||||
String bestMatch;
|
|
||||||
Double similarity;
|
|
||||||
}
|
|
||||||
@ -1,5 +1,7 @@
|
|||||||
package com.magamochi.model.entity;
|
package com.magamochi.model.entity;
|
||||||
|
|
||||||
|
import com.magamochi.content.model.entity.Image;
|
||||||
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
@ -47,14 +49,5 @@ public class Manga {
|
|||||||
|
|
||||||
private OffsetDateTime publishedTo;
|
private OffsetDateTime publishedTo;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "manga")
|
|
||||||
private List<MangaAuthor> mangaAuthors;
|
|
||||||
|
|
||||||
@OneToMany(mappedBy = "manga")
|
|
||||||
private List<MangaGenre> mangaGenres;
|
|
||||||
|
|
||||||
@OneToMany(mappedBy = "manga")
|
|
||||||
private List<MangaAlternativeTitle> alternativeTitles;
|
|
||||||
|
|
||||||
@Builder.Default private Integer chapterCount = 0;
|
@Builder.Default private Integer chapterCount = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
package com.magamochi.model.repository;
|
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaAlternativeTitle;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface MangaAlternativeTitlesRepository
|
|
||||||
extends JpaRepository<MangaAlternativeTitle, Long> {}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.magamochi.model.repository;
|
|
||||||
|
|
||||||
import com.magamochi.model.entity.Author;
|
|
||||||
import com.magamochi.model.entity.Manga;
|
|
||||||
import com.magamochi.model.entity.MangaAuthor;
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface MangaAuthorRepository extends JpaRepository<MangaAuthor, Long> {
|
|
||||||
Optional<MangaAuthor> findByMangaAndAuthor(Manga manga, Author author);
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
package com.magamochi.model.repository;
|
|
||||||
|
|
||||||
import com.magamochi.model.entity.MangaChapter;
|
|
||||||
import com.magamochi.model.entity.MangaChapterImage;
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface MangaChapterImageRepository extends JpaRepository<MangaChapterImage, Long> {
|
|
||||||
List<MangaChapterImage> findAllByMangaChapter(MangaChapter mangaChapter);
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.magamochi.model.repository;
|
|
||||||
|
|
||||||
import com.magamochi.model.entity.Genre;
|
|
||||||
import com.magamochi.model.entity.Manga;
|
|
||||||
import com.magamochi.model.entity.MangaGenre;
|
|
||||||
import java.util.Optional;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface MangaGenreRepository extends JpaRepository<MangaGenre, Long> {
|
|
||||||
Optional<MangaGenre> findByMangaAndGenre(Manga manga, Genre genre);
|
|
||||||
}
|
|
||||||
@ -2,8 +2,8 @@ package com.magamochi.model.specification;
|
|||||||
|
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.model.entity.Author;
|
||||||
import com.magamochi.model.dto.MangaListFilterDTO;
|
import com.magamochi.model.dto.MangaListFilterDTO;
|
||||||
import com.magamochi.model.entity.Author;
|
|
||||||
import com.magamochi.model.entity.Manga;
|
import com.magamochi.model.entity.Manga;
|
||||||
import com.magamochi.user.model.entity.User;
|
import com.magamochi.user.model.entity.User;
|
||||||
import jakarta.persistence.criteria.*;
|
import jakarta.persistence.criteria.*;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.magamochi.queue;
|
package com.magamochi.queue;
|
||||||
|
|
||||||
|
import com.magamochi.content.service.MangaChapterService;
|
||||||
import com.magamochi.model.dto.MangaChapterDownloadCommand;
|
import com.magamochi.model.dto.MangaChapterDownloadCommand;
|
||||||
import com.magamochi.service.MangaChapterService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
package com.magamochi.service;
|
|
||||||
|
|
||||||
import com.magamochi.model.dto.GenreDTO;
|
|
||||||
import com.magamochi.model.repository.GenreRepository;
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GenreService {
|
|
||||||
private final GenreRepository genreRepository;
|
|
||||||
|
|
||||||
public List<GenreDTO> getGenres() {
|
|
||||||
var genres = genreRepository.findAll();
|
|
||||||
|
|
||||||
return genres.stream().map(GenreDTO::from).toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
package com.magamochi.service;
|
|
||||||
|
|
||||||
import com.magamochi.exception.NotFoundException;
|
|
||||||
import com.magamochi.model.entity.Language;
|
|
||||||
import com.magamochi.model.repository.LanguageRepository;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class LanguageService {
|
|
||||||
public final LanguageRepository languageRepository;
|
|
||||||
|
|
||||||
public Language getOrThrow(String code) {
|
|
||||||
return languageRepository
|
|
||||||
.findByCodeIgnoreCase(code)
|
|
||||||
.orElseThrow(() -> new NotFoundException("Language with code " + code + " not found"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,12 +5,13 @@ 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.model.dto.TitleMatchRequestDTO;
|
import com.magamochi.ingestion.service.TitleMatcherService;
|
||||||
|
import com.magamochi.ingestion.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.ingestion.model.entity.MangaImportReview;
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import com.magamochi.model.repository.MangaImportReviewRepository;
|
import com.magamochi.ingestion.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;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -60,7 +61,7 @@ public class MangaCreationService {
|
|||||||
.toList())
|
.toList())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
if (!titleMatchResponse.isMatchFound()) {
|
if (!titleMatchResponse.matchFound()) {
|
||||||
createMangaImportReview(title, url, provider);
|
createMangaImportReview(title, url, provider);
|
||||||
log.warn("No match found for manga with title {}", title);
|
log.warn("No match found for manga with title {}", title);
|
||||||
return null;
|
return null;
|
||||||
@ -73,7 +74,7 @@ public class MangaCreationService {
|
|||||||
results.titles().stream()
|
results.titles().stream()
|
||||||
.map(JikanClient.SearchResponse.MangaData.TitleData::title)
|
.map(JikanClient.SearchResponse.MangaData.TitleData::title)
|
||||||
.toList()
|
.toList()
|
||||||
.contains(titleMatchResponse.getBestMatch()))
|
.contains(titleMatchResponse.bestMatch()))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (resultOptional.isEmpty()) {
|
if (resultOptional.isEmpty()) {
|
||||||
createMangaImportReview(title, url, provider);
|
createMangaImportReview(title, url, provider);
|
||||||
|
|||||||
@ -4,9 +4,20 @@ import static java.util.Objects.isNull;
|
|||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.RateLimiter;
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
|
import com.magamochi.catalog.service.*;
|
||||||
import com.magamochi.client.AniListClient;
|
import com.magamochi.client.AniListClient;
|
||||||
import com.magamochi.client.JikanClient;
|
import com.magamochi.client.JikanClient;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapterImage;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterImageRepository;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterRepository;
|
||||||
|
import com.magamochi.content.service.ImageService;
|
||||||
|
import com.magamochi.content.service.LanguageService;
|
||||||
import com.magamochi.exception.NotFoundException;
|
import com.magamochi.exception.NotFoundException;
|
||||||
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
|
import com.magamochi.ingestion.model.repository.MangaProviderRepository;
|
||||||
|
import com.magamochi.ingestion.service.ProviderService;
|
||||||
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.*;
|
||||||
@ -20,6 +31,7 @@ import java.time.ZoneOffset;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
@ -38,20 +50,22 @@ public class MangaImportService {
|
|||||||
private final ImageService imageService;
|
private final ImageService imageService;
|
||||||
private final LanguageService languageService;
|
private final LanguageService languageService;
|
||||||
|
|
||||||
private final GenreRepository genreRepository;
|
private final GenreService genreService;
|
||||||
private final MangaGenreRepository mangaGenreRepository;
|
private final MangaGenreService mangaGenreService;
|
||||||
|
|
||||||
|
private final AuthorService authorService;
|
||||||
|
private final MangaAuthorService mangaAuthorService;
|
||||||
|
|
||||||
private final MangaProviderRepository mangaProviderRepository;
|
private final MangaProviderRepository mangaProviderRepository;
|
||||||
private final AuthorRepository authorRepository;
|
|
||||||
private final MangaAuthorRepository mangaAuthorRepository;
|
|
||||||
private final MangaChapterRepository mangaChapterRepository;
|
private final MangaChapterRepository mangaChapterRepository;
|
||||||
private final MangaRepository mangaRepository;
|
private final MangaRepository mangaRepository;
|
||||||
|
|
||||||
private final JikanClient jikanClient;
|
private final JikanClient jikanClient;
|
||||||
private final AniListClient aniListClient;
|
private final AniListClient aniListClient;
|
||||||
private final MangaChapterImageRepository mangaChapterImageRepository;
|
private final MangaChapterImageRepository mangaChapterImageRepository;
|
||||||
private final MangaAlternativeTitlesRepository mangaAlternativeTitlesRepository;
|
|
||||||
|
|
||||||
private final RateLimiter jikanRateLimiter;
|
private final RateLimiter jikanRateLimiter;
|
||||||
|
private final MangaAlternativeTitleService mangaAlternativeTitleService;
|
||||||
|
|
||||||
public void importMangaFiles(String malId, List<MultipartFile> files) {
|
public void importMangaFiles(String malId, List<MultipartFile> files) {
|
||||||
log.info("Importing manga files for MAL ID {}", malId);
|
log.info("Importing manga files for MAL ID {}", malId);
|
||||||
@ -105,8 +119,8 @@ public class MangaImportService {
|
|||||||
var chapterImage =
|
var chapterImage =
|
||||||
MangaChapterImage.builder()
|
MangaChapterImage.builder()
|
||||||
.position(position++)
|
.position(position++)
|
||||||
.image(image)
|
.imageId(image.getId())
|
||||||
.mangaChapter(chapter)
|
.mangaChapterId(chapter.getId())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
allChapterImages.add(chapterImage);
|
allChapterImages.add(chapterImage);
|
||||||
@ -177,50 +191,30 @@ public class MangaImportService {
|
|||||||
manga.setPublishedTo(mangaData.data().published().to());
|
manga.setPublishedTo(mangaData.data().published().to());
|
||||||
manga.setChapterCount(mangaData.data().chapters());
|
manga.setChapterCount(mangaData.data().chapters());
|
||||||
|
|
||||||
var authors =
|
var authorIds =
|
||||||
mangaData.data().authors().stream()
|
mangaData.data().authors().stream()
|
||||||
.map(
|
.map(
|
||||||
authorData ->
|
authorData ->
|
||||||
authorRepository
|
authorService.findOrCreateAuthor(authorData.mal_id(), authorData.name()))
|
||||||
.findByMalId(authorData.mal_id())
|
.collect(Collectors.toSet());
|
||||||
.orElseGet(
|
|
||||||
() ->
|
|
||||||
authorRepository.save(
|
|
||||||
Author.builder()
|
|
||||||
.malId(authorData.mal_id())
|
|
||||||
.name(authorData.name())
|
|
||||||
.build())))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
updateMangaAuthors(manga, authors);
|
mangaAuthorService.saveOrUpdateMangaAuthors(manga.getId(), authorIds);
|
||||||
|
|
||||||
var genres =
|
var genreIds =
|
||||||
mangaData.data().genres().stream()
|
mangaData.data().genres().stream()
|
||||||
.map(
|
.map(genreData -> genreService.findOrCreateGenre(genreData.mal_id(), genreData.name()))
|
||||||
genreData ->
|
.collect(Collectors.toSet());
|
||||||
genreRepository
|
|
||||||
.findByMalId(genreData.mal_id())
|
|
||||||
.orElseGet(
|
|
||||||
() ->
|
|
||||||
genreRepository.save(
|
|
||||||
Genre.builder()
|
|
||||||
.malId(genreData.mal_id())
|
|
||||||
.name(genreData.name())
|
|
||||||
.build())))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
updateMangaGenres(manga, genres);
|
mangaGenreService.saveOrUpdateMangaGenres(manga.getId(), genreIds);
|
||||||
|
|
||||||
if (isNull(manga.getCoverImage())) {
|
if (isNull(manga.getCoverImage())) {
|
||||||
downloadCoverImage(manga, mangaData.data().images().jpg().large_image_url());
|
downloadCoverImage(manga, mangaData.data().images().jpg().large_image_url());
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangaEntity = mangaRepository.save(manga);
|
mangaRepository.save(manga);
|
||||||
var alternativeTitles =
|
|
||||||
mangaData.data().title_synonyms().stream()
|
mangaAlternativeTitleService.saveOrUpdateMangaAlternativeTitles(
|
||||||
.map(at -> MangaAlternativeTitle.builder().manga(mangaEntity).title(at).build())
|
manga.getId(), mangaData.data().title_synonyms());
|
||||||
.toList();
|
|
||||||
mangaAlternativeTitlesRepository.saveAll(alternativeTitles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFromAniList(Manga manga) throws IOException, URISyntaxException {
|
private void updateFromAniList(Manga manga) throws IOException, URISyntaxException {
|
||||||
@ -261,31 +255,22 @@ public class MangaImportService {
|
|||||||
manga.setPublishedTo(convertFuzzyDate(media.endDate()));
|
manga.setPublishedTo(convertFuzzyDate(media.endDate()));
|
||||||
manga.setChapterCount(media.chapters());
|
manga.setChapterCount(media.chapters());
|
||||||
|
|
||||||
var authors =
|
var authorIds =
|
||||||
media.staff().edges().stream()
|
media.staff().edges().stream()
|
||||||
.filter(edge -> isAuthorRole(edge.role()))
|
.filter(edge -> isAuthorRole(edge.role()))
|
||||||
.map(edge -> edge.node().name().full())
|
.map(edge -> edge.node().name().full())
|
||||||
.distinct()
|
.distinct()
|
||||||
.map(
|
.map(name -> authorService.findOrCreateAuthor(null, name))
|
||||||
name ->
|
.collect(Collectors.toSet());
|
||||||
authorRepository
|
|
||||||
.findByName(name)
|
|
||||||
.orElseGet(
|
|
||||||
() -> authorRepository.save(Author.builder().name(name).build())))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
updateMangaAuthors(manga, authors);
|
mangaAuthorService.saveOrUpdateMangaAuthors(manga.getId(), authorIds);
|
||||||
|
|
||||||
var genres =
|
var genreIds =
|
||||||
media.genres().stream()
|
media.genres().stream()
|
||||||
.map(
|
.map(name -> genreService.findOrCreateGenre(null, name))
|
||||||
name ->
|
.collect(Collectors.toSet());
|
||||||
genreRepository
|
|
||||||
.findByName(name)
|
|
||||||
.orElseGet(() -> genreRepository.save(Genre.builder().name(name).build())))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
updateMangaGenres(manga, genres);
|
mangaGenreService.saveOrUpdateMangaGenres(manga.getId(), genreIds);
|
||||||
|
|
||||||
if (isNull(manga.getCoverImage())) {
|
if (isNull(manga.getCoverImage())) {
|
||||||
downloadCoverImage(manga, media.coverImage().large());
|
downloadCoverImage(manga, media.coverImage().large());
|
||||||
@ -324,36 +309,6 @@ public class MangaImportService {
|
|||||||
ZoneOffset.UTC);
|
ZoneOffset.UTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMangaAuthors(Manga manga, List<Author> authors) {
|
|
||||||
var mangaAuthors =
|
|
||||||
authors.stream()
|
|
||||||
.map(
|
|
||||||
author ->
|
|
||||||
mangaAuthorRepository
|
|
||||||
.findByMangaAndAuthor(manga, author)
|
|
||||||
.orElseGet(
|
|
||||||
() ->
|
|
||||||
mangaAuthorRepository.save(
|
|
||||||
MangaAuthor.builder().manga(manga).author(author).build())))
|
|
||||||
.toList();
|
|
||||||
manga.setMangaAuthors(mangaAuthors);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateMangaGenres(Manga manga, List<Genre> genres) {
|
|
||||||
var mangaGenres =
|
|
||||||
genres.stream()
|
|
||||||
.map(
|
|
||||||
genre ->
|
|
||||||
mangaGenreRepository
|
|
||||||
.findByMangaAndGenre(manga, genre)
|
|
||||||
.orElseGet(
|
|
||||||
() ->
|
|
||||||
mangaGenreRepository.save(
|
|
||||||
MangaGenre.builder().manga(manga).genre(genre).build())))
|
|
||||||
.toList();
|
|
||||||
manga.setMangaGenres(mangaGenres);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void downloadCoverImage(Manga manga, String imageUrl)
|
private void downloadCoverImage(Manga manga, String imageUrl)
|
||||||
throws IOException, URISyntaxException {
|
throws IOException, URISyntaxException {
|
||||||
var inputStream =
|
var inputStream =
|
||||||
@ -378,8 +333,8 @@ public class MangaImportService {
|
|||||||
mangaChapter.setTitle(chapter.chapterTitle());
|
mangaChapter.setTitle(chapter.chapterTitle());
|
||||||
mangaChapter.setUrl(chapter.chapterUrl());
|
mangaChapter.setUrl(chapter.chapterUrl());
|
||||||
|
|
||||||
var language = languageService.getOrThrow(chapter.languageCode());
|
var languageId = languageService.getLanguageIdOrThrow(chapter.languageCode());
|
||||||
mangaChapter.setLanguage(language);
|
mangaChapter.setLanguageId(languageId);
|
||||||
|
|
||||||
if (nonNull(chapter.chapter())) {
|
if (nonNull(chapter.chapter())) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -2,9 +2,10 @@ 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.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.repository.MangaProviderRepository;
|
import com.magamochi.ingestion.model.repository.MangaProviderRepository;
|
||||||
import com.magamochi.service.providers.PagedContentProviderFactory;
|
import com.magamochi.ingestion.service.ProviderService;
|
||||||
|
import com.magamochi.ingestion.service.providers.PagedContentProviderFactory;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|||||||
@ -2,14 +2,23 @@ package com.magamochi.service;
|
|||||||
|
|
||||||
import static java.util.Objects.nonNull;
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
|
import com.magamochi.catalog.service.MangaAlternativeTitleService;
|
||||||
|
import com.magamochi.catalog.service.MangaAuthorService;
|
||||||
|
import com.magamochi.catalog.service.MangaGenreService;
|
||||||
import com.magamochi.client.NtfyClient;
|
import com.magamochi.client.NtfyClient;
|
||||||
|
import com.magamochi.content.model.dto.MangaChapterDTO;
|
||||||
|
import com.magamochi.content.model.entity.MangaChapter;
|
||||||
|
import com.magamochi.content.model.repository.MangaChapterRepository;
|
||||||
|
import com.magamochi.content.service.LanguageService;
|
||||||
import com.magamochi.exception.NotFoundException;
|
import com.magamochi.exception.NotFoundException;
|
||||||
|
import com.magamochi.ingestion.model.entity.MangaProvider;
|
||||||
|
import com.magamochi.ingestion.model.repository.MangaProviderRepository;
|
||||||
import com.magamochi.model.dto.*;
|
import com.magamochi.model.dto.*;
|
||||||
import com.magamochi.model.entity.*;
|
import com.magamochi.model.entity.*;
|
||||||
import com.magamochi.model.repository.*;
|
import com.magamochi.model.repository.*;
|
||||||
import com.magamochi.model.specification.MangaSpecification;
|
import com.magamochi.model.specification.MangaSpecification;
|
||||||
import com.magamochi.queue.MangaChapterDownloadProducer;
|
import com.magamochi.queue.MangaChapterDownloadProducer;
|
||||||
import com.magamochi.service.providers.ContentProviderFactory;
|
import com.magamochi.ingestion.service.providers.ContentProviderFactory;
|
||||||
import com.magamochi.user.service.UserService;
|
import com.magamochi.user.service.UserService;
|
||||||
import com.magamochi.userinteraction.service.UserFavoriteMangaService;
|
import com.magamochi.userinteraction.service.UserFavoriteMangaService;
|
||||||
import com.magamochi.userinteraction.service.UserFollowMangaService;
|
import com.magamochi.userinteraction.service.UserFollowMangaService;
|
||||||
@ -35,11 +44,17 @@ public class MangaService {
|
|||||||
private final MangaRepository mangaRepository;
|
private final MangaRepository mangaRepository;
|
||||||
private final MangaProviderRepository mangaProviderRepository;
|
private final MangaProviderRepository mangaProviderRepository;
|
||||||
|
|
||||||
|
private final MangaGenreService mangaGenreService;
|
||||||
|
private final MangaAuthorService mangaAuthorService;
|
||||||
|
private final MangaAlternativeTitleService mangaAlternativeTitleService;
|
||||||
|
|
||||||
private final ContentProviderFactory contentProviderFactory;
|
private final ContentProviderFactory contentProviderFactory;
|
||||||
|
|
||||||
private final MangaChapterDownloadProducer mangaChapterDownloadProducer;
|
private final MangaChapterDownloadProducer mangaChapterDownloadProducer;
|
||||||
private final MangaChapterRepository mangaChapterRepository;
|
private final MangaChapterRepository mangaChapterRepository;
|
||||||
|
|
||||||
|
private final LanguageService languageService;
|
||||||
|
|
||||||
private final NtfyClient ntfyClient;
|
private final NtfyClient ntfyClient;
|
||||||
|
|
||||||
public void fetchAllNotDownloadedChapters(Long mangaProviderId) {
|
public void fetchAllNotDownloadedChapters(Long mangaProviderId) {
|
||||||
@ -73,8 +88,10 @@ public class MangaService {
|
|||||||
.findAll(specification, pageable)
|
.findAll(specification, pageable)
|
||||||
.map(
|
.map(
|
||||||
manga -> {
|
manga -> {
|
||||||
|
var genres = mangaGenreService.getMangaGenres(manga.getId());
|
||||||
|
var authors = mangaAuthorService.getMangaAuthors(manga.getId());
|
||||||
var favorite = favoriteMangasIds.contains(manga.getId());
|
var favorite = favoriteMangasIds.contains(manga.getId());
|
||||||
return MangaListDTO.from(manga, favorite);
|
return MangaListDTO.from(manga, favorite, genres, authors);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +100,11 @@ public class MangaService {
|
|||||||
|
|
||||||
return mangaProvider.getMangaChapters().stream()
|
return mangaProvider.getMangaChapters().stream()
|
||||||
.sorted(Comparator.comparing(MangaChapter::getId))
|
.sorted(Comparator.comparing(MangaChapter::getId))
|
||||||
.map(MangaChapterDTO::from)
|
.map(
|
||||||
|
mangaChapter -> {
|
||||||
|
var language = languageService.getLanguageOrThrow(mangaChapter.getLanguageId());
|
||||||
|
return MangaChapterDTO.from(mangaChapter, language);
|
||||||
|
})
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,10 +118,17 @@ public class MangaService {
|
|||||||
var followingMangaIds =
|
var followingMangaIds =
|
||||||
nonNull(user) ? userFollowMangaService.getFollowedMangaIdsForLoggedUser() : Set.of();
|
nonNull(user) ? userFollowMangaService.getFollowedMangaIdsForLoggedUser() : Set.of();
|
||||||
|
|
||||||
|
var genres = mangaGenreService.getMangaGenres(manga.getId());
|
||||||
|
var authors = mangaAuthorService.getMangaAuthors(manga.getId());
|
||||||
|
var alternativeTitles = mangaAlternativeTitleService.getMangaAlternativeTitles(manga.getId());
|
||||||
|
|
||||||
return MangaDTO.from(
|
return MangaDTO.from(
|
||||||
manga,
|
manga,
|
||||||
favoriteMangasIds.contains(manga.getId()),
|
favoriteMangasIds.contains(manga.getId()),
|
||||||
followingMangaIds.contains(manga.getId()));
|
followingMangaIds.contains(manga.getId()),
|
||||||
|
genres,
|
||||||
|
authors,
|
||||||
|
alternativeTitles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetchFollowedMangaChapters(Long mangaProviderId) {
|
public void fetchFollowedMangaChapters(Long mangaProviderId) {
|
||||||
|
|||||||
@ -6,12 +6,12 @@ import static java.util.Objects.nonNull;
|
|||||||
import com.magamochi.exception.NotFoundException;
|
import com.magamochi.exception.NotFoundException;
|
||||||
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.ingestion.model.entity.MangaProvider;
|
||||||
import com.magamochi.model.entity.Provider;
|
import com.magamochi.ingestion.model.entity.Provider;
|
||||||
import com.magamochi.model.enumeration.ProviderStatus;
|
import com.magamochi.ingestion.model.enumeration.ProviderStatus;
|
||||||
import com.magamochi.model.repository.MangaProviderRepository;
|
import com.magamochi.ingestion.model.repository.MangaProviderRepository;
|
||||||
import com.magamochi.model.repository.ProviderRepository;
|
import com.magamochi.ingestion.model.repository.ProviderRepository;
|
||||||
import com.magamochi.service.providers.ManualImportContentProviderFactory;
|
import com.magamochi.ingestion.service.providers.ManualImportContentProviderFactory;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ 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.ingestion.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 com.magamochi.userinteraction.service.UserFollowMangaService;
|
import com.magamochi.userinteraction.service.UserFollowMangaService;
|
||||||
|
|||||||
@ -2,10 +2,10 @@ package com.magamochi.task;
|
|||||||
|
|
||||||
import com.magamochi.exception.NotFoundException;
|
import com.magamochi.exception.NotFoundException;
|
||||||
import com.magamochi.model.dto.MangaListUpdateCommand;
|
import com.magamochi.model.dto.MangaListUpdateCommand;
|
||||||
import com.magamochi.model.repository.ProviderRepository;
|
import com.magamochi.ingestion.model.repository.ProviderRepository;
|
||||||
import com.magamochi.queue.UpdateMangaListProducer;
|
import com.magamochi.queue.UpdateMangaListProducer;
|
||||||
import com.magamochi.service.providers.PagedContentProvider;
|
import com.magamochi.ingestion.service.providers.PagedContentProvider;
|
||||||
import com.magamochi.service.providers.PagedContentProviderFactory;
|
import com.magamochi.ingestion.service.providers.PagedContentProviderFactory;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user