feature/adjustments #23
@ -6,6 +6,7 @@ import com.magamochi.mangamochi.model.entity.Manga;
|
|||||||
import com.magamochi.mangamochi.model.entity.MangaAlternativeTitle;
|
import com.magamochi.mangamochi.model.entity.MangaAlternativeTitle;
|
||||||
import com.magamochi.mangamochi.model.entity.MangaChapter;
|
import com.magamochi.mangamochi.model.entity.MangaChapter;
|
||||||
import com.magamochi.mangamochi.model.entity.MangaProvider;
|
import com.magamochi.mangamochi.model.entity.MangaProvider;
|
||||||
|
import com.magamochi.mangamochi.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;
|
||||||
@ -53,6 +54,7 @@ public record MangaDTO(
|
|||||||
public record MangaProviderDTO(
|
public record MangaProviderDTO(
|
||||||
@NotNull long id,
|
@NotNull long id,
|
||||||
@NotBlank String providerName,
|
@NotBlank String providerName,
|
||||||
|
@NotNull ProviderStatus providerStatus,
|
||||||
@NotNull Integer chaptersAvailable,
|
@NotNull Integer chaptersAvailable,
|
||||||
@NotNull Integer chaptersDownloaded,
|
@NotNull Integer chaptersDownloaded,
|
||||||
@NotNull Boolean supportsChapterFetch) {
|
@NotNull Boolean supportsChapterFetch) {
|
||||||
@ -64,6 +66,7 @@ public record MangaDTO(
|
|||||||
return new MangaProviderDTO(
|
return new MangaProviderDTO(
|
||||||
mangaProvider.getId(),
|
mangaProvider.getId(),
|
||||||
mangaProvider.getProvider().getName(),
|
mangaProvider.getProvider().getName(),
|
||||||
|
mangaProvider.getProvider().getStatus(),
|
||||||
chaptersAvailable,
|
chaptersAvailable,
|
||||||
chaptersDownloaded,
|
chaptersDownloaded,
|
||||||
mangaProvider.getProvider().getSupportsChapterFetch());
|
mangaProvider.getProvider().getSupportsChapterFetch());
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.magamochi.mangamochi.model.dto.MangaChapterDownloadCommand;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -12,8 +13,11 @@ import org.springframework.stereotype.Service;
|
|||||||
public class MangaChapterDownloadProducer {
|
public class MangaChapterDownloadProducer {
|
||||||
private final RabbitTemplate rabbitTemplate;
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Value("${rabbit-mq.queues.manga-chapter-download}")
|
||||||
|
private String mangaChapterDownloadQueue;
|
||||||
|
|
||||||
public void sendMangaChapterDownloadCommand(MangaChapterDownloadCommand command) {
|
public void sendMangaChapterDownloadCommand(MangaChapterDownloadCommand command) {
|
||||||
rabbitTemplate.convertAndSend("${rabbit-mq.queues.manga-chapter-download}", command);
|
rabbitTemplate.convertAndSend(mangaChapterDownloadQueue, command);
|
||||||
log.info("Sent manga chapter download command: {}", command);
|
log.info("Sent manga chapter download command: {}", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.magamochi.mangamochi.model.dto.UpdateMangaDataCommand;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -12,8 +13,11 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UpdateMangaDataProducer {
|
public class UpdateMangaDataProducer {
|
||||||
private final RabbitTemplate rabbitTemplate;
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Value("${rabbit-mq.queues.manga-data-update}")
|
||||||
|
private String mangaDataUpdateQueue;
|
||||||
|
|
||||||
public void sendUpdateMangaDataCommand(UpdateMangaDataCommand command) {
|
public void sendUpdateMangaDataCommand(UpdateMangaDataCommand command) {
|
||||||
rabbitTemplate.convertAndSend("${rabbit-mq.queues.manga-data-update}", command);
|
rabbitTemplate.convertAndSend(mangaDataUpdateQueue, command);
|
||||||
log.info("Sent update manga data command: {}", command);
|
log.info("Sent update manga data command: {}", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.magamochi.mangamochi.model.dto.UpdateMangaFollowChapterListCommand;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -12,8 +13,11 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UpdateMangaFollowChapterListProducer {
|
public class UpdateMangaFollowChapterListProducer {
|
||||||
private final RabbitTemplate rabbitTemplate;
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Value("${rabbit-mq.queues.manga-follow-update-chapter}")
|
||||||
|
private String mangaFollowUpdateChapterQueue;
|
||||||
|
|
||||||
public void sendUpdateMangaFollowChapterListCommand(UpdateMangaFollowChapterListCommand command) {
|
public void sendUpdateMangaFollowChapterListCommand(UpdateMangaFollowChapterListCommand command) {
|
||||||
rabbitTemplate.convertAndSend("${rabbit-mq.queues.manga-follow-update-chapter}", command);
|
rabbitTemplate.convertAndSend(mangaFollowUpdateChapterQueue, command);
|
||||||
log.info("Sent update followed manga chapter list command: {}", command);
|
log.info("Sent update followed manga chapter list command: {}", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.magamochi.mangamochi.model.dto.MangaListUpdateCommand;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -12,8 +13,11 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UpdateMangaListProducer {
|
public class UpdateMangaListProducer {
|
||||||
private final RabbitTemplate rabbitTemplate;
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Value("${rabbit-mq.queues.manga-list-update}")
|
||||||
|
private String mangaListUpdateQueue;
|
||||||
|
|
||||||
public void sendUpdateMangaListCommand(MangaListUpdateCommand command) {
|
public void sendUpdateMangaListCommand(MangaListUpdateCommand command) {
|
||||||
rabbitTemplate.convertAndSend("${rabbit-mq.queues.manga-list-update}", command);
|
rabbitTemplate.convertAndSend(mangaListUpdateQueue, command);
|
||||||
log.info("Sent update manga list command: {}", command);
|
log.info("Sent update manga list command: {}", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.magamochi.mangamochi.service.providers;
|
package com.magamochi.mangamochi.service.providers;
|
||||||
|
|
||||||
public class ContentProviders {
|
public class ContentProviders {
|
||||||
public static final String MANGA_LIVRE = "Manga Livre";
|
public static final String MANGA_LIVRE_TO = "Manga Livre.to";
|
||||||
public static final String MANGA_LIVRE_BLOG = "Manga Livre Blog";
|
public static final String MANGA_LIVRE_BLOG = "Manga Livre Blog";
|
||||||
public static final String MANGA_DEX = "MangaDex";
|
public static final String MANGA_DEX = "MangaDex";
|
||||||
public static final String PINK_ROSA_SCAN = "Pink Rosa Scan";
|
public static final String PINK_ROSA_SCAN = "Pink Rosa Scan";
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.magamochi.mangamochi.service.providers.impl;
|
package com.magamochi.mangamochi.service.providers.impl;
|
||||||
|
|
||||||
|
import static java.util.Objects.nonNull;
|
||||||
|
|
||||||
import com.magamochi.mangamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
import com.magamochi.mangamochi.model.dto.ContentProviderMangaChapterResponseDTO;
|
||||||
import com.magamochi.mangamochi.model.dto.ContentProviderMangaInfoResponseDTO;
|
import com.magamochi.mangamochi.model.dto.ContentProviderMangaInfoResponseDTO;
|
||||||
import com.magamochi.mangamochi.model.entity.MangaProvider;
|
import com.magamochi.mangamochi.model.entity.MangaProvider;
|
||||||
@ -16,10 +18,11 @@ import lombok.extern.log4j.Log4j2;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@Service(ContentProviders.MANGA_LIVRE)
|
@Service(ContentProviders.MANGA_LIVRE_TO)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MangaLivreProvider implements ContentProvider, PagedContentProvider {
|
public class MangaLivreProvider implements ContentProvider, PagedContentProvider {
|
||||||
private final String url = "https://mangalivre.tv/manga/";
|
private final String url = "https://mangalivre.to/manga/";
|
||||||
|
private final int MANGAS_PER_PAGE = 10;
|
||||||
|
|
||||||
private final FlareService flareService;
|
private final FlareService flareService;
|
||||||
|
|
||||||
@ -27,22 +30,27 @@ public class MangaLivreProvider implements ContentProvider, PagedContentProvider
|
|||||||
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) {
|
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) {
|
||||||
log.info(
|
log.info(
|
||||||
"Getting available chapters from {}, manga {}",
|
"Getting available chapters from {}, manga {}",
|
||||||
ContentProviders.MANGA_LIVRE,
|
ContentProviders.MANGA_LIVRE_TO,
|
||||||
provider.getManga().getTitle());
|
provider.getManga().getTitle());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var document =
|
var document =
|
||||||
flareService.getContentAsJsoupDocument(provider.getUrl(), ContentProviders.MANGA_LIVRE);
|
flareService.getContentAsJsoupDocument(
|
||||||
|
provider.getUrl(), ContentProviders.MANGA_LIVRE_TO);
|
||||||
|
|
||||||
var chapterItems = document.getElementsByClass("wp-manga-chapter");
|
var chapterBoxes =
|
||||||
|
document.selectFirst("div.listing-chapters-wrap").select("div.chapter-box");
|
||||||
|
|
||||||
return chapterItems.stream()
|
return chapterBoxes.stream()
|
||||||
.map(
|
.map(
|
||||||
chapterItemElement -> {
|
chapterBox -> {
|
||||||
var linkElement = chapterItemElement.getElementsByTag("a").getFirst();
|
var linkElement = chapterBox.selectFirst("a");
|
||||||
|
|
||||||
|
var url = linkElement.attr("href");
|
||||||
|
var title = linkElement.text();
|
||||||
|
|
||||||
return new ContentProviderMangaChapterResponseDTO(
|
return new ContentProviderMangaChapterResponseDTO(
|
||||||
linkElement.text(), linkElement.attr("href"), null, null);
|
title.trim(), url.trim(), null, null);
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
@ -53,21 +61,19 @@ public class MangaLivreProvider implements ContentProvider, PagedContentProvider
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Integer, String> getChapterImagesUrls(String chapterUrl) {
|
public Map<Integer, String> getChapterImagesUrls(String chapterUrl) {
|
||||||
log.info("Getting images from {}, url {}", ContentProviders.MANGA_LIVRE, chapterUrl);
|
log.info("Getting images from {}, url {}", ContentProviders.MANGA_LIVRE_TO, chapterUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var document =
|
var document =
|
||||||
flareService.getContentAsJsoupDocument(chapterUrl, ContentProviders.MANGA_LIVRE);
|
flareService.getContentAsJsoupDocument(chapterUrl, ContentProviders.MANGA_LIVRE_TO);
|
||||||
|
|
||||||
var chapterImagesContainer = document.getElementsByClass("chapter-images").getFirst();
|
var chapterImagesElements = document.select("div.reading-content img.wp-manga-chapter-img");
|
||||||
var chapterImagesElements = chapterImagesContainer.getElementsByClass("page-break");
|
|
||||||
|
|
||||||
var imageUrls =
|
var imageUrls =
|
||||||
chapterImagesElements.stream()
|
chapterImagesElements.stream()
|
||||||
.map(
|
.map(
|
||||||
chapterImagesElement -> {
|
chapterImagesElement -> {
|
||||||
var imageElement = chapterImagesElement.getElementsByTag("img").getFirst();
|
return chapterImagesElement.attr("src");
|
||||||
return imageElement.attr("src");
|
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@ -77,54 +83,40 @@ public class MangaLivreProvider implements ContentProvider, PagedContentProvider
|
|||||||
Collectors.toMap(
|
Collectors.toMap(
|
||||||
i -> i, imageUrls::get, (existing, replacement) -> existing, LinkedHashMap::new));
|
i -> i, imageUrls::get, (existing, replacement) -> existing, LinkedHashMap::new));
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
log.error("Error parsing mangas from MangaLivre", e);
|
log.error("Error parsing manga images from MangaLivre", e);
|
||||||
return Map.of();
|
return Map.of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ContentProviderMangaInfoResponseDTO> getMangasFromPage(Integer page) {
|
public List<ContentProviderMangaInfoResponseDTO> getMangasFromPage(Integer page) {
|
||||||
log.info("Getting mangas from {}, page {}", ContentProviders.MANGA_LIVRE, page);
|
log.info("Getting mangas from {}, page {}", ContentProviders.MANGA_LIVRE_TO, page);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var document =
|
var document =
|
||||||
flareService.getContentAsJsoupDocument(
|
flareService.getContentAsJsoupDocument(
|
||||||
url + "page/" + page, ContentProviders.MANGA_LIVRE);
|
url + "page/" + page, ContentProviders.MANGA_LIVRE_TO);
|
||||||
|
|
||||||
var mangaElements = document.getElementsByClass("manga__item");
|
var mangaElements = document.select("div.page-item-detail.manga");
|
||||||
|
|
||||||
return mangaElements.stream()
|
return mangaElements.stream()
|
||||||
.map(
|
.map(
|
||||||
element -> {
|
element -> {
|
||||||
var mangaTitleElement =
|
var linkElement = element.selectFirst(".item-thumb > a");
|
||||||
element
|
|
||||||
.getElementsByClass("manga__content")
|
|
||||||
.getFirst()
|
|
||||||
.getElementsByClass("manga__content_item")
|
|
||||||
.getFirst()
|
|
||||||
.getElementsByClass("post-title font-title")
|
|
||||||
.getFirst()
|
|
||||||
.getElementsByTag("h2")
|
|
||||||
.getFirst();
|
|
||||||
|
|
||||||
var linkElement = mangaTitleElement.getElementsByTag("a").getFirst();
|
|
||||||
var url = linkElement.attr("href");
|
var url = linkElement.attr("href");
|
||||||
var title = linkElement.text().trim();
|
|
||||||
|
|
||||||
var imageElement =
|
var title = linkElement.attr("title");
|
||||||
element
|
|
||||||
.getElementsByClass("manga__thumb")
|
// Fallback: If 'title' attribute is empty, try the <img> tag's 'alt' or 'title'
|
||||||
.getFirst()
|
if (title.isBlank()) {
|
||||||
.getElementsByClass("manga__thumb_item")
|
var imgElement = linkElement.selectFirst("img");
|
||||||
.getFirst()
|
if (nonNull(imgElement)) {
|
||||||
.getElementsByTag("a")
|
title = imgElement.attr("alt");
|
||||||
.getFirst()
|
}
|
||||||
.getElementsByTag("img")
|
}
|
||||||
.getFirst();
|
|
||||||
var imgUrl = imageElement.attr("src");
|
|
||||||
|
|
||||||
return new ContentProviderMangaInfoResponseDTO(
|
return new ContentProviderMangaInfoResponseDTO(
|
||||||
title, url, imgUrl, MangaStatus.UNKNOWN);
|
title.trim(), url.trim(), null, MangaStatus.UNKNOWN);
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
@ -135,17 +127,16 @@ public class MangaLivreProvider implements ContentProvider, PagedContentProvider
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer getTotalPages() {
|
public Integer getTotalPages() {
|
||||||
log.info("Getting total pages for {}", ContentProviders.MANGA_LIVRE);
|
log.info("Getting total pages for {}", ContentProviders.MANGA_LIVRE_TO);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var document = flareService.getContentAsJsoupDocument(url, ContentProviders.MANGA_LIVRE);
|
var document = flareService.getContentAsJsoupDocument(url, ContentProviders.MANGA_LIVRE_TO);
|
||||||
|
|
||||||
var navLinks = document.getElementsByClass("wp-pagenavi").getFirst();
|
var fullText = document.selectFirst("div.h4:contains(resultados)").text();
|
||||||
var lastPageElement = navLinks.getElementsByClass("last").getFirst();
|
var numberString = fullText.replace("resultados", "").trim().replaceAll("[^0-9]", "");
|
||||||
var links = lastPageElement.attr("href");
|
var totalMangas = Integer.parseInt(numberString);
|
||||||
|
|
||||||
var totalPages = links.replaceAll("\\D+", "");
|
return (int) Math.ceil((double) totalMangas / MANGAS_PER_PAGE);
|
||||||
return Integer.parseInt(totalPages);
|
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
log.error("Error parsing total pages from MangaLivre", e);
|
log.error("Error parsing total pages from MangaLivre", e);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.magamochi.mangamochi.task;
|
|||||||
|
|
||||||
import com.magamochi.mangamochi.model.dto.UpdateMangaFollowChapterListCommand;
|
import com.magamochi.mangamochi.model.dto.UpdateMangaFollowChapterListCommand;
|
||||||
import com.magamochi.mangamochi.model.entity.Manga;
|
import com.magamochi.mangamochi.model.entity.Manga;
|
||||||
|
import com.magamochi.mangamochi.model.enumeration.ProviderStatus;
|
||||||
import com.magamochi.mangamochi.model.repository.MangaRepository;
|
import com.magamochi.mangamochi.model.repository.MangaRepository;
|
||||||
import com.magamochi.mangamochi.queue.UpdateMangaFollowChapterListProducer;
|
import com.magamochi.mangamochi.queue.UpdateMangaFollowChapterListProducer;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -43,10 +44,14 @@ public class MangaFollowUpdateTask {
|
|||||||
log.info("Fetching available mangas for followed Manga {}", manga.getTitle());
|
log.info("Fetching available mangas for followed Manga {}", manga.getTitle());
|
||||||
|
|
||||||
var mangaProviders = manga.getMangaProviders();
|
var mangaProviders = manga.getMangaProviders();
|
||||||
mangaProviders.forEach(
|
|
||||||
mangaProvider ->
|
mangaProviders.stream()
|
||||||
producer.sendUpdateMangaFollowChapterListCommand(
|
.filter(
|
||||||
new UpdateMangaFollowChapterListCommand(mangaProvider.getId())));
|
mangaProvider -> mangaProvider.getProvider().getStatus().equals(ProviderStatus.ACTIVE))
|
||||||
|
.forEach(
|
||||||
|
mangaProvider ->
|
||||||
|
producer.sendUpdateMangaFollowChapterListCommand(
|
||||||
|
new UpdateMangaFollowChapterListCommand(mangaProvider.getId())));
|
||||||
|
|
||||||
log.info("Followed Manga ({}) chapter list update queued.", manga.getTitle());
|
log.info("Followed Manga ({}) chapter list update queued.", manga.getTitle());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
DO
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
_target_provider_name TEXT := 'Manga Livre';
|
||||||
|
_target_provider_id BIGINT;
|
||||||
|
_deleted_chapters_count INTEGER;
|
||||||
|
_deleted_manga_providers_count INTEGER;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT id
|
||||||
|
INTO _target_provider_id
|
||||||
|
FROM providers
|
||||||
|
WHERE name = _target_provider_name;
|
||||||
|
|
||||||
|
IF _target_provider_id IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Provider with name "%" not found.', _target_provider_name;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE providers SET status = 'INACTIVE' WHERE id = _target_provider_id;
|
||||||
|
|
||||||
|
-- Delete non-downloaded manga chapters associated with the target provider
|
||||||
|
DELETE
|
||||||
|
FROM manga_chapters mc
|
||||||
|
USING manga_provider mp
|
||||||
|
WHERE mc.manga_provider_id = mp.id
|
||||||
|
AND mp.provider_id = _target_provider_id
|
||||||
|
AND mc.downloaded = FALSE;
|
||||||
|
|
||||||
|
GET DIAGNOSTICS _deleted_chapters_count = ROW_COUNT;
|
||||||
|
RAISE NOTICE 'Deleted % non-downloaded chapters for provider ID %.', _deleted_chapters_count, _target_provider_id;
|
||||||
|
|
||||||
|
-- Delete MangaProvider records ONLY if NO chapters
|
||||||
|
DELETE
|
||||||
|
FROM manga_provider mp
|
||||||
|
WHERE mp.provider_id = _target_provider_id
|
||||||
|
AND NOT EXISTS (SELECT 1
|
||||||
|
FROM manga_chapters mc
|
||||||
|
WHERE mc.manga_provider_id = mp.id);
|
||||||
|
|
||||||
|
GET DIAGNOSTICS _deleted_manga_providers_count = ROW_COUNT;
|
||||||
|
RAISE NOTICE 'Deleted % manga_provider entries', _deleted_manga_providers_count;
|
||||||
|
END
|
||||||
|
$$;
|
||||||
Loading…
x
Reference in New Issue
Block a user