439 lines
16 KiB
Java
439 lines
16 KiB
Java
// package com.magamochi.service;
|
|
//
|
|
// import static java.util.Objects.isNull;
|
|
// import static java.util.Objects.nonNull;
|
|
//
|
|
// import com.google.common.util.concurrent.RateLimiter;
|
|
// import com.magamochi.catalog.model.entity.Genre;
|
|
// import com.magamochi.catalog.model.repository.GenreRepository;
|
|
// import com.magamochi.catalog.client.AniListClient;
|
|
// import com.magamochi.catalog.client.JikanClient;
|
|
// import com.magamochi.common.exception.NotFoundException;
|
|
// import com.magamochi.ingestion.model.entity.ContentProvider;
|
|
// import com.magamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
|
// import com.magamochi.model.entity.*;
|
|
// import com.magamochi.model.repository.*;
|
|
// import com.magamochi.catalog.util.DoubleUtil;
|
|
// import java.io.*;
|
|
// import java.net.URI;
|
|
// import java.net.URISyntaxException;
|
|
// import java.net.URL;
|
|
// import java.time.OffsetDateTime;
|
|
// import java.time.ZoneOffset;
|
|
// import java.util.ArrayList;
|
|
// import java.util.Comparator;
|
|
// import java.util.List;
|
|
// import java.util.stream.IntStream;
|
|
// import java.util.zip.ZipEntry;
|
|
// import java.util.zip.ZipInputStream;
|
|
// import lombok.RequiredArgsConstructor;
|
|
// import lombok.extern.log4j.Log4j2;
|
|
// import org.apache.commons.lang3.StringUtils;
|
|
// import org.springframework.stereotype.Service;
|
|
// import org.springframework.web.multipart.MultipartFile;
|
|
//
|
|
// @Log4j2
|
|
//// @Service
|
|
// @RequiredArgsConstructor
|
|
// public class MangaImportService {
|
|
// private final ProviderService providerService;
|
|
// private final MangaCreationService mangaCreationService;
|
|
// private final ImageService imageService;
|
|
// private final LanguageService languageService;
|
|
//
|
|
// private final GenreRepository genreRepository;
|
|
// private final MangaGenreRepository mangaGenreRepository;
|
|
// private final MangaContentProviderRepository mangaContentProviderRepository;
|
|
// private final AuthorRepository authorRepository;
|
|
// private final MangaAuthorRepository mangaAuthorRepository;
|
|
// private final MangaChapterRepository mangaChapterRepository;
|
|
// private final MangaRepository mangaRepository;
|
|
//
|
|
// private final JikanClient jikanClient;
|
|
// private final AniListClient aniListClient;
|
|
// private final MangaChapterImageRepository mangaChapterImageRepository;
|
|
// private final MangaAlternativeTitlesRepository mangaAlternativeTitlesRepository;
|
|
//
|
|
// private final RateLimiter jikanRateLimiter;
|
|
//
|
|
// public void importMangaFiles(String malId, List<MultipartFile> files) {
|
|
// log.info("Importing manga files for MAL ID {}", malId);
|
|
// var provider = providerService.getOrCreateProvider("Manual Import", false);
|
|
//
|
|
// jikanRateLimiter.acquire();
|
|
// var mangaData = jikanClient.getMangaById(Long.parseLong(malId));
|
|
//
|
|
// var mangaProvider = getOrCreateMangaProvider(mangaData.data().title(), provider);
|
|
//
|
|
// var sortedFiles =
|
|
// files.stream().sorted(Comparator.comparing(MultipartFile::getName)).toList();
|
|
//
|
|
// IntStream.rangeClosed(1, sortedFiles.size())
|
|
// .forEach(
|
|
// fileIndex -> {
|
|
// var file = sortedFiles.get(fileIndex - 1);
|
|
// log.info(
|
|
// "Importing file {}/{}: {}, for Mangá {}",
|
|
// fileIndex,
|
|
// sortedFiles.size(),
|
|
// file.getOriginalFilename(),
|
|
// mangaProvider.getManga().getTitle());
|
|
//
|
|
// var chapter =
|
|
// persistMangaChapter(
|
|
// mangaProvider,
|
|
// new ContentProviderMangaChapterResponseDTO(
|
|
// removeFileExtension(file.getOriginalFilename()),
|
|
// "manual_" + file.getOriginalFilename(),
|
|
// file.getOriginalFilename(),
|
|
// "en-US"));
|
|
//
|
|
// List<MangaChapterImage> allChapterImages = new ArrayList<>();
|
|
// try (InputStream is = file.getInputStream();
|
|
// ZipInputStream zis = new ZipInputStream(is)) {
|
|
// ZipEntry entry;
|
|
// var position = 0;
|
|
//
|
|
// while ((entry = zis.getNextEntry()) != null) {
|
|
// if (entry.isDirectory()) {
|
|
// continue;
|
|
// }
|
|
//
|
|
// var os = new ByteArrayOutputStream();
|
|
// zis.transferTo(os);
|
|
// var bytes = os.toByteArray();
|
|
//
|
|
// var image =
|
|
// imageService.uploadImage(bytes, "image/jpeg", "chapter/" + chapter.getId());
|
|
//
|
|
// var chapterImage =
|
|
// MangaChapterImage.builder()
|
|
// .position(position++)
|
|
// .image(image)
|
|
// .mangaChapter(chapter)
|
|
// .build();
|
|
//
|
|
// allChapterImages.add(chapterImage);
|
|
// zis.closeEntry();
|
|
// }
|
|
//
|
|
// log.info("Chapter images added for chapter {}", chapter.getTitle());
|
|
// } catch (IOException e) {
|
|
// throw new RuntimeException(e);
|
|
// }
|
|
//
|
|
// mangaChapterImageRepository.saveAll(allChapterImages);
|
|
// chapter.setDownloaded(true);
|
|
// mangaChapterRepository.save(chapter);
|
|
// });
|
|
//
|
|
// log.info("Import manga files for MAL ID {} completed.", malId);
|
|
// }
|
|
//
|
|
// public void updateMangaData(Long mangaId) {
|
|
// var manga =
|
|
// mangaRepository
|
|
// .findById(mangaId)
|
|
// .orElseThrow(() -> new NotFoundException("Manga not found for ID: " + mangaId));
|
|
//
|
|
// updateMangaData(manga);
|
|
// }
|
|
//
|
|
// public void updateMangaData(Manga manga) {
|
|
// log.info("Updating manga {}", manga.getTitle());
|
|
//
|
|
// if (nonNull(manga.getMalId())) {
|
|
// try {
|
|
// updateFromJikan(manga);
|
|
// return;
|
|
// } catch (Exception e) {
|
|
// log.warn(
|
|
// "Error updating manga data from Jikan for manga {}. Trying AniList... Error: {}",
|
|
// manga.getTitle(),
|
|
// e.getMessage());
|
|
// }
|
|
// }
|
|
//
|
|
// if (nonNull(manga.getAniListId())) {
|
|
// try {
|
|
// updateFromAniList(manga);
|
|
// return;
|
|
// } catch (Exception e) {
|
|
// log.warn(
|
|
// "Error updating manga data from AniList for manga {}. Error: {}",
|
|
// manga.getTitle(),
|
|
// e.getMessage());
|
|
// }
|
|
// }
|
|
//
|
|
// log.warn(
|
|
// "Could not update manga data for {}. No provider data available/found.",
|
|
// manga.getTitle());
|
|
// }
|
|
//
|
|
// private void updateFromJikan(Manga manga) throws IOException, URISyntaxException {
|
|
// jikanRateLimiter.acquire();
|
|
// var mangaData = jikanClient.getMangaById(manga.getMalId());
|
|
//
|
|
// manga.setSynopsis(mangaData.data().synopsis());
|
|
// manga.setStatus(mangaData.data().status());
|
|
// manga.setScore(DoubleUtil.round((double) mangaData.data().score(), 2));
|
|
// manga.setPublishedFrom(mangaData.data().published().from());
|
|
// manga.setPublishedTo(mangaData.data().published().to());
|
|
// manga.setChapterCount(mangaData.data().chapters());
|
|
//
|
|
// var authors =
|
|
// mangaData.data().authors().stream()
|
|
// .map(
|
|
// authorData ->
|
|
// authorRepository
|
|
// .findByMalId(authorData.mal_id())
|
|
// .orElseGet(
|
|
// () ->
|
|
// authorRepository.save(
|
|
// Author.builder()
|
|
// .malId(authorData.mal_id())
|
|
// .name(authorData.name())
|
|
// .build())))
|
|
// .toList();
|
|
//
|
|
// updateMangaAuthors(manga, authors);
|
|
//
|
|
// var genres =
|
|
// mangaData.data().genres().stream()
|
|
// .map(
|
|
// genreData ->
|
|
// genreRepository
|
|
// .findByMalId(genreData.mal_id())
|
|
// .orElseGet(
|
|
// () ->
|
|
// genreRepository.save(
|
|
// Genre.builder()
|
|
// .malId(genreData.mal_id())
|
|
// .name(genreData.name())
|
|
// .build())))
|
|
// .toList();
|
|
//
|
|
// updateMangaGenres(manga, genres);
|
|
//
|
|
// if (isNull(manga.getCoverImage())) {
|
|
// downloadCoverImage(manga, mangaData.data().images().jpg().large_image_url());
|
|
// }
|
|
//
|
|
// var mangaEntity = mangaRepository.save(manga);
|
|
// var alternativeTitles =
|
|
// mangaData.data().title_synonyms().stream()
|
|
// .map(at -> MangaAlternativeTitle.builder().manga(mangaEntity).title(at).build())
|
|
// .toList();
|
|
// mangaAlternativeTitlesRepository.saveAll(alternativeTitles);
|
|
// }
|
|
//
|
|
// private void updateFromAniList(Manga manga) throws IOException, URISyntaxException {
|
|
// var query =
|
|
// """
|
|
// query ($id: Int) {
|
|
// Media (id: $id, type: MANGA) {
|
|
// startDate { year month day }
|
|
// endDate { year month day }
|
|
// description
|
|
// status
|
|
// averageScore
|
|
// chapters
|
|
// coverImage { large }
|
|
// genres
|
|
// staff {
|
|
// edges {
|
|
// role
|
|
// node {
|
|
// name {
|
|
// full
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// """;
|
|
// var request =
|
|
// new AniListClient.GraphQLRequest(
|
|
// query, new AniListClient.GraphQLRequest.Variables(manga.getAniListId()));
|
|
// var media = aniListClient.getManga(request).data().Media();
|
|
//
|
|
// manga.setSynopsis(media.description());
|
|
// manga.setStatus(mapAniListStatus(media.status()));
|
|
// manga.setScore(DoubleUtil.round((double) media.averageScore() / 10, 2)); // 0-100 -> 0-10
|
|
// manga.setPublishedFrom(convertFuzzyDate(media.startDate()));
|
|
// manga.setPublishedTo(convertFuzzyDate(media.endDate()));
|
|
// manga.setChapterCount(media.chapters());
|
|
//
|
|
// var authors =
|
|
// media.staff().edges().stream()
|
|
// .filter(edge -> isAuthorRole(edge.role()))
|
|
// .map(edge -> edge.node().name().full())
|
|
// .distinct()
|
|
// .map(
|
|
// name ->
|
|
// authorRepository
|
|
// .findByName(name)
|
|
// .orElseGet(
|
|
// () -> authorRepository.save(Author.builder().name(name).build())))
|
|
// .toList();
|
|
//
|
|
// updateMangaAuthors(manga, authors);
|
|
//
|
|
// var genres =
|
|
// media.genres().stream()
|
|
// .map(
|
|
// name ->
|
|
// genreRepository
|
|
// .findByName(name)
|
|
// .orElseGet(() ->
|
|
// genreRepository.save(Genre.builder().name(name).build())))
|
|
// .toList();
|
|
//
|
|
// updateMangaGenres(manga, genres);
|
|
//
|
|
// if (isNull(manga.getCoverImage())) {
|
|
// downloadCoverImage(manga, media.coverImage().large());
|
|
// }
|
|
//
|
|
// mangaRepository.save(manga);
|
|
// }
|
|
//
|
|
// private boolean isAuthorRole(String role) {
|
|
// return role.equalsIgnoreCase("Story & Art")
|
|
// || role.equalsIgnoreCase("Story")
|
|
// || role.equalsIgnoreCase("Art");
|
|
// }
|
|
//
|
|
// private String mapAniListStatus(String status) {
|
|
// return switch (status) {
|
|
// case "RELEASING" -> "Publishing";
|
|
// case "FINISHED" -> "Finished";
|
|
// case "NOT_YET_RELEASED" -> "Not yet published";
|
|
// default -> "Unknown";
|
|
// };
|
|
// }
|
|
//
|
|
// private OffsetDateTime convertFuzzyDate(AniListClient.MangaResponse.Manga.FuzzyDate date) {
|
|
// if (isNull(date) || isNull(date.year())) {
|
|
// return null;
|
|
// }
|
|
// return OffsetDateTime.of(
|
|
// date.year(),
|
|
// isNull(date.month()) ? 1 : date.month(),
|
|
// isNull(date.day()) ? 1 : date.day(),
|
|
// 0,
|
|
// 0,
|
|
// 0,
|
|
// 0,
|
|
// 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)
|
|
// throws IOException, URISyntaxException {
|
|
// var inputStream =
|
|
// new BufferedInputStream(new URL(new URI(imageUrl).toASCIIString()).openStream());
|
|
//
|
|
// var bytes = inputStream.readAllBytes();
|
|
//
|
|
// inputStream.close();
|
|
// var image = imageService.uploadImage(bytes, "image/jpeg", "cover");
|
|
//
|
|
// manga.setCoverImage(image);
|
|
// }
|
|
//
|
|
// public MangaChapter persistMangaChapter(
|
|
// MangaContentProvider mangaContentProvider, ContentProviderMangaChapterResponseDTO chapter) {
|
|
// var mangaChapter =
|
|
// mangaChapterRepository
|
|
// .findByMangaContentProviderAndUrlIgnoreCase(mangaContentProvider,
|
|
// chapter.url())
|
|
// .orElseGet(MangaChapter::new);
|
|
//
|
|
// mangaChapter.setMangaContentProvider(mangaContentProvider);
|
|
// mangaChapter.setTitle(chapter.title());
|
|
// mangaChapter.setUrl(chapter.url());
|
|
//
|
|
// var language = languageService.getOrThrow(chapter.languageCode());
|
|
// mangaChapter.setLanguage(language);
|
|
//
|
|
// if (nonNull(chapter.chapter())) {
|
|
// try {
|
|
// mangaChapter.setChapterNumber(Integer.parseInt(chapter.chapter()));
|
|
// } catch (NumberFormatException e) {
|
|
// log.warn(
|
|
// "Could not parse chapter number {} from manga {}",
|
|
// chapter.chapter(),
|
|
// mangaContentProvider.getManga().getTitle());
|
|
// }
|
|
// }
|
|
//
|
|
// return mangaChapterRepository.save(mangaChapter);
|
|
// }
|
|
//
|
|
// private MangaContentProvider getOrCreateMangaProvider(
|
|
// String title, ContentProvider contentProvider) {
|
|
// return mangaContentProviderRepository
|
|
// .findByMangaTitleIgnoreCaseAndContentProvider(title, contentProvider)
|
|
// .orElseGet(
|
|
// () -> {
|
|
// jikanRateLimiter.acquire();
|
|
// var manga = mangaCreationService.getOrCreateManga(title, "manual", contentProvider);
|
|
//
|
|
// return mangaContentProviderRepository.save(
|
|
// MangaContentProvider.builder()
|
|
// .manga(manga)
|
|
// .mangaTitle(manga.getTitle())
|
|
// .contentProvider(contentProvider)
|
|
// .url("manual")
|
|
// .build());
|
|
// });
|
|
// }
|
|
//
|
|
// private String removeFileExtension(String filename) {
|
|
// if (StringUtils.isBlank(filename)) {
|
|
// return filename;
|
|
// }
|
|
//
|
|
// int lastDotIndex = filename.lastIndexOf('.');
|
|
//
|
|
// // No dot, or dot is the first character (like .gitignore)
|
|
// if (lastDotIndex <= 0) {
|
|
// return filename;
|
|
// }
|
|
//
|
|
// return filename.substring(0, lastDotIndex);
|
|
// }
|
|
// }
|