feat: update endpoints and remove authorization from MangaDexClient and Provider
This commit is contained in:
parent
28e71403c1
commit
8182db8cb7
4
.env
4
.env
@ -6,8 +6,8 @@ MINIO_ENDPOINT=http://omv.badger-pirarucu.ts.net:9000
|
|||||||
MINIO_USER=admin
|
MINIO_USER=admin
|
||||||
MINIO_PASS=!E9v4i0v3
|
MINIO_PASS=!E9v4i0v3
|
||||||
|
|
||||||
WEBSCRAPPER_ENDPOINT=http://localhost:8090/url
|
WEBSCRAPPER_ENDPOINT=http://mangamochi.badger-pirarucu.ts.net:8090/url
|
||||||
MANGAMATCHER_ENDPOINT=http://127.0.0.1:8000/match-title
|
MANGAMATCHER_ENDPOINT=http://mangamochi.badger-pirarucu.ts.net:8000/match-title
|
||||||
|
|
||||||
MANGADEX_USER=rocverde
|
MANGADEX_USER=rocverde
|
||||||
MANGADEX_PASS=!A3u8e4s0
|
MANGADEX_PASS=!A3u8e4s0
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
package com.magamochi.mangamochi.client;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@FeignClient(name = "mangaDexAuthentication", url = "https://auth.mangadex.org")
|
|
||||||
public interface MangaDexAuthenticationClient {
|
|
||||||
|
|
||||||
// @Headers("Content-Type: application/x-www-form-urlencoded")
|
|
||||||
@PostMapping(
|
|
||||||
value = "/realms/mangadex/protocol/openid-connect/token",
|
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
|
||||||
AuthTokenResponse authenticate(@RequestBody MultiValueMap<String, String> form);
|
|
||||||
|
|
||||||
public record AuthTokenResponse(
|
|
||||||
@JsonProperty("access_token") String accessToken,
|
|
||||||
@JsonProperty("refresh_token") String refreshToken) {}
|
|
||||||
|
|
||||||
public static MultiValueMap<String, String> build(
|
|
||||||
String username, String password, String clientId, String clientSecret) {
|
|
||||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
|
||||||
form.add("grant_type", "password");
|
|
||||||
form.add("username", username);
|
|
||||||
form.add("password", password);
|
|
||||||
form.add("client_id", clientId);
|
|
||||||
form.add("client_secret", clientSecret);
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,23 +9,17 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
@FeignClient(name = "mangaDex", url = "https://api.mangadex.org")
|
@FeignClient(name = "mangaDex", url = "https://api.mangadex.org")
|
||||||
public interface MangaDexClient {
|
public interface MangaDexClient {
|
||||||
@GetMapping("/manga/{id}")
|
@GetMapping("/manga/{id}")
|
||||||
MangaDexMangaDTO getManga(
|
MangaDexMangaDTO getManga(@PathVariable UUID id);
|
||||||
@PathVariable UUID id, @RequestHeader("Authorization") String authorization);
|
|
||||||
|
@GetMapping("/manga/{id}/feed")
|
||||||
|
MangaDexMangaFeedDTO getMangaFeed(@PathVariable UUID id);
|
||||||
|
|
||||||
@GetMapping("/manga/{id}/feed")
|
@GetMapping("/manga/{id}/feed")
|
||||||
MangaDexMangaFeedDTO getMangaFeed(
|
MangaDexMangaFeedDTO getMangaFeed(
|
||||||
@PathVariable UUID id, @RequestHeader("Authorization") String authorization);
|
@PathVariable UUID id, @RequestParam int limit, @RequestParam int offset);
|
||||||
|
|
||||||
@GetMapping("/manga/{id}/feed")
|
|
||||||
MangaDexMangaFeedDTO getMangaFeed(
|
|
||||||
@PathVariable UUID id,
|
|
||||||
@RequestParam int limit,
|
|
||||||
@RequestParam int offset,
|
|
||||||
@RequestHeader("Authorization") String authorization);
|
|
||||||
|
|
||||||
@GetMapping("/at-home/server/{chapterId}")
|
@GetMapping("/at-home/server/{chapterId}")
|
||||||
MangaChapterDataDTO getMangaChapter(
|
MangaChapterDataDTO getMangaChapter(@PathVariable UUID chapterId);
|
||||||
@PathVariable UUID chapterId, @RequestHeader("Authorization") String authorization);
|
|
||||||
|
|
||||||
record MangaDexMangaFeedDTO(
|
record MangaDexMangaFeedDTO(
|
||||||
List<MangaFeedData> data, Integer limit, Integer offset, Integer total) {
|
List<MangaFeedData> data, Integer limit, Integer offset, Integer total) {
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.magamochi.mangamochi.service.providers.impl;
|
|||||||
import static java.util.Objects.isNull;
|
import static java.util.Objects.isNull;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.RateLimiter;
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
import com.magamochi.mangamochi.client.MangaDexAuthenticationClient;
|
|
||||||
import com.magamochi.mangamochi.client.MangaDexClient;
|
import com.magamochi.mangamochi.client.MangaDexClient;
|
||||||
import com.magamochi.mangamochi.exception.NotFoundException;
|
import com.magamochi.mangamochi.exception.NotFoundException;
|
||||||
import com.magamochi.mangamochi.exception.UnprocessableException;
|
import com.magamochi.mangamochi.exception.UnprocessableException;
|
||||||
@ -23,34 +22,18 @@ import java.util.stream.Collectors;
|
|||||||
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;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@Service(ContentProviders.MANGA_DEX)
|
@Service(ContentProviders.MANGA_DEX)
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MangaDexProvider implements ContentProvider {
|
public class MangaDexProvider implements ContentProvider {
|
||||||
@Value("${manga-dex.username}")
|
|
||||||
private String mangaDexUsername;
|
|
||||||
|
|
||||||
@Value("${manga-dex.password}")
|
|
||||||
private String mangaDexPassword;
|
|
||||||
|
|
||||||
@Value("${manga-dex.client-id}")
|
|
||||||
private String mangaDexClientId;
|
|
||||||
|
|
||||||
@Value("${manga-dex.client-secret}")
|
|
||||||
private String mangaDexClientSecret;
|
|
||||||
|
|
||||||
private final MangaDexClient mangaDexClient;
|
private final MangaDexClient mangaDexClient;
|
||||||
private final MangaDexAuthenticationClient mangaDexAuthenticationClient;
|
|
||||||
private final MangaCreationService mangaCreationService;
|
private final MangaCreationService mangaCreationService;
|
||||||
private final ProviderRepository providerRepository;
|
private final ProviderRepository providerRepository;
|
||||||
private final MangaProviderRepository mangaProviderRepository;
|
private final MangaProviderRepository mangaProviderRepository;
|
||||||
|
|
||||||
RateLimiter rateLimiter = RateLimiter.create(1);
|
RateLimiter rateLimiter = RateLimiter.create(3);
|
||||||
|
|
||||||
private String authorizationToken;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ContentProviderMangaInfoResponseDTO> getAvailableMangas() {
|
public List<ContentProviderMangaInfoResponseDTO> getAvailableMangas() {
|
||||||
@ -62,58 +45,66 @@ public class MangaDexProvider implements ContentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) {
|
public List<ContentProviderMangaChapterResponseDTO> getAvailableChapters(MangaProvider provider) {
|
||||||
rateLimiter.acquire();
|
try {
|
||||||
var response =
|
rateLimiter.acquire();
|
||||||
mangaDexClient.getMangaFeed(UUID.fromString(provider.getUrl()), getAuthorizationToken());
|
var response = mangaDexClient.getMangaFeed(UUID.fromString(provider.getUrl()));
|
||||||
|
|
||||||
var mangas = new ArrayList<>(response.data());
|
var mangas = new ArrayList<>(response.data());
|
||||||
var totalPages = (int) Math.ceil((double) response.total() / 100); // Default page size is 100
|
var totalPages = (int) Math.ceil((double) response.total() / 500);
|
||||||
|
|
||||||
IntStream.range(1, totalPages)
|
try {
|
||||||
.forEach(
|
|
||||||
i -> {
|
|
||||||
rateLimiter.acquire();
|
|
||||||
|
|
||||||
var pagedResponse =
|
IntStream.range(1, totalPages)
|
||||||
mangaDexClient.getMangaFeed(
|
.parallel()
|
||||||
UUID.fromString(provider.getUrl()), 100, i * 100, getAuthorizationToken());
|
.forEach(
|
||||||
|
i -> {
|
||||||
|
rateLimiter.acquire();
|
||||||
|
|
||||||
mangas.addAll(pagedResponse.data());
|
var pagedResponse =
|
||||||
});
|
mangaDexClient.getMangaFeed(UUID.fromString(provider.getUrl()), 500, i * 500);
|
||||||
|
|
||||||
// TODO this is filtering only pt-br chapters for now, we may want to make this configurable
|
mangas.addAll(pagedResponse.data());
|
||||||
// later
|
});
|
||||||
return mangas.stream()
|
} catch (Exception e) {
|
||||||
.filter(
|
log.warn(e.getMessage());
|
||||||
c ->
|
}
|
||||||
c.type().equals("chapter")
|
|
||||||
&& c.attributes().isUnavailable().equals(Boolean.FALSE)
|
// TODO this is filtering only pt-br chapters for now, we may want to make this configurable
|
||||||
&& c.attributes().translatedLanguage().equals("pt-br"))
|
// later
|
||||||
.sorted(
|
return mangas.stream()
|
||||||
(o1, o2) -> {
|
.filter(
|
||||||
try {
|
c ->
|
||||||
Float chapter1 = Float.parseFloat(o1.attributes().chapter());
|
c.type().equals("chapter")
|
||||||
Float chapter2 = Float.parseFloat(o2.attributes().chapter());
|
&& c.attributes().isUnavailable().equals(Boolean.FALSE)
|
||||||
return chapter2.compareTo(chapter1);
|
&& c.attributes().translatedLanguage().equals("pt-br"))
|
||||||
} catch (NumberFormatException e) {
|
.sorted(
|
||||||
return o2.attributes().chapter().compareTo(o1.attributes().chapter());
|
(o1, o2) -> {
|
||||||
}
|
try {
|
||||||
})
|
Float chapter1 = Float.parseFloat(o1.attributes().chapter());
|
||||||
.map(
|
Float chapter2 = Float.parseFloat(o2.attributes().chapter());
|
||||||
c ->
|
return chapter2.compareTo(chapter1);
|
||||||
new ContentProviderMangaChapterResponseDTO(
|
} catch (NumberFormatException e) {
|
||||||
c.attributes().chapter() + " - " + c.attributes().title(),
|
return o2.attributes().chapter().compareTo(o1.attributes().chapter());
|
||||||
c.id().toString(),
|
}
|
||||||
c.attributes().chapter(),
|
})
|
||||||
c.attributes().translatedLanguage()))
|
.map(
|
||||||
.toList();
|
c ->
|
||||||
|
new ContentProviderMangaChapterResponseDTO(
|
||||||
|
c.attributes().chapter() + " - " + c.attributes().title(),
|
||||||
|
c.id().toString(),
|
||||||
|
c.attributes().chapter(),
|
||||||
|
c.attributes().translatedLanguage()))
|
||||||
|
.toList();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn(e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Integer, String> getChapterImagesUrls(String chapterUrl) {
|
public Map<Integer, String> getChapterImagesUrls(String chapterUrl) {
|
||||||
rateLimiter.acquire();
|
rateLimiter.acquire();
|
||||||
var chapter =
|
var chapter = mangaDexClient.getMangaChapter(UUID.fromString(chapterUrl));
|
||||||
mangaDexClient.getMangaChapter(UUID.fromString(chapterUrl), getAuthorizationToken());
|
|
||||||
|
|
||||||
var chapterImageHashes =
|
var chapterImageHashes =
|
||||||
chapter.chapter().data().stream()
|
chapter.chapter().data().stream()
|
||||||
@ -131,10 +122,8 @@ public class MangaDexProvider implements ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ImportMangaDexResponseDTO importManga(UUID id) {
|
public ImportMangaDexResponseDTO importManga(UUID id) {
|
||||||
var token = getAuthorizationToken();
|
|
||||||
|
|
||||||
rateLimiter.acquire();
|
rateLimiter.acquire();
|
||||||
var resultData = mangaDexClient.getManga(id, token).data();
|
var resultData = mangaDexClient.getManga(id).data();
|
||||||
|
|
||||||
if (resultData.attributes().title().isEmpty()) {
|
if (resultData.attributes().title().isEmpty()) {
|
||||||
throw new UnprocessableException("Manga title not found for ID: " + id);
|
throw new UnprocessableException("Manga title not found for ID: " + id);
|
||||||
@ -174,19 +163,4 @@ public class MangaDexProvider implements ContentProvider {
|
|||||||
|
|
||||||
return new ImportMangaDexResponseDTO(manga.getId());
|
return new ImportMangaDexResponseDTO(manga.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAuthorizationToken() {
|
|
||||||
if (isNull(authorizationToken)) {
|
|
||||||
rateLimiter.acquire();
|
|
||||||
|
|
||||||
var authResponse =
|
|
||||||
mangaDexAuthenticationClient.authenticate(
|
|
||||||
MangaDexAuthenticationClient.build(
|
|
||||||
mangaDexUsername, mangaDexPassword, mangaDexClientId, mangaDexClientSecret));
|
|
||||||
|
|
||||||
authorizationToken = "Bearer " + authResponse.accessToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
return authorizationToken;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ spring:
|
|||||||
openfeign:
|
openfeign:
|
||||||
client:
|
client:
|
||||||
config:
|
config:
|
||||||
default:
|
web-scrapper:
|
||||||
connect-timeout: 120000
|
connect-timeout: 120000
|
||||||
read-timeout: 120000
|
read-timeout: 120000
|
||||||
|
|
||||||
@ -44,11 +44,5 @@ jwt:
|
|||||||
secret: mySecretKeymySecretKeymySecretKeymySecretKeymySecretKeymySecretKey
|
secret: mySecretKeymySecretKeymySecretKeymySecretKeymySecretKeymySecretKey
|
||||||
expiration: 86400000 # 24 hours in milliseconds
|
expiration: 86400000 # 24 hours in milliseconds
|
||||||
|
|
||||||
manga-dex:
|
|
||||||
username: ${MANGADEX_USER}
|
|
||||||
password: ${MANGADEX_PASS}
|
|
||||||
client-id: ${MANGADEX_CLIENT_ID}
|
|
||||||
client-secret: ${MANGADEX_CLIENT_SECRET}
|
|
||||||
|
|
||||||
manga-matcher:
|
manga-matcher:
|
||||||
endpoint: ${MANGAMATCHER_ENDPOINT}
|
endpoint: ${MANGAMATCHER_ENDPOINT}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user