Compare commits

...

12 Commits

Author SHA1 Message Date
1e42f24e3a Use logstash as logging destination 2025-09-14 01:58:32 +05:00
740e1a0279 Use buildx caching in docker mvn package 2025-09-07 01:06:08 +05:00
13be17fa8f Use docker shared network instead of localhost 2025-09-01 19:21:31 +05:00
21199307c7 Use external docker network 2025-09-01 19:19:47 +05:00
e07f48f39d Change compose service name 2025-08-28 17:23:56 +05:00
53dcde6bd9 Exclude error message and change application name to anyame-kodik-search-backend 2025-08-28 17:22:27 +05:00
eca6f50730 Bump spring-boot 3.5.0 -> 3.5.5 2025-08-28 12:36:59 +05:00
4d99a59947 Add .env.example and add eureka client 2025-08-28 11:47:39 +05:00
f2eee1752d Include "season" in anime identifier 2025-08-10 16:15:23 +05:00
9cc7cede69 [Fix] Allow only specific types only in search results (#2)
Reviewed-on: #2
Co-authored-by: bivashy <botyrbojey@gmail.com>
Co-committed-by: bivashy <botyrbojey@gmail.com>
2025-07-19 18:50:29 +00:00
9540a71307 [Fix] Return unique search results (#1)
Reviewed-on: #1
Co-authored-by: bivashy <botyrbojey@gmail.com>
Co-committed-by: bivashy <botyrbojey@gmail.com>
2025-07-19 18:41:34 +00:00
55bbb79510 Fix compose image name 2025-07-14 00:45:08 +05:00
8 changed files with 92 additions and 15 deletions

3
.env.example Normal file
View File

@ -0,0 +1,3 @@
KODIK_TOKEN=YOUR_KODIK_TOKEN
EUREKA_SCHEMA=http
EUREKA_HOST=anyame-vue-bff:8080

View File

@ -2,9 +2,9 @@
FROM maven:3.9.6-eclipse-temurin-21 AS builder
WORKDIR /workspace
COPY pom.xml .
RUN mvn dependency:go-offline -B
RUN --mount=type=cache,target=/root/.m2 mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
RUN --mount=type=cache,target=/root/.m2 mvn clean package -DskipTests
# Create optimized runtime
FROM eclipse-temurin:21 AS app-build

View File

@ -1,11 +1,15 @@
services:
search:
image: anyame-search:latest
kodik-search:
image: anyame-kodik-search:latest
ports:
- 8080:8080
env_file: .env
networks:
- anyame
- anyame-shared
- elk-network
networks:
anyame:
driver: bridge
anyame-shared:
external: true
elk-network:
external: true

18
pom.xml
View File

@ -6,13 +6,13 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
<version>3.5.5</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.backend.search.kodik.service</groupId>
<artifactId>anyame-backend</artifactId>
<artifactId>anyame-kodik-search-backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>anyame-backend</name>
<name>anyame-kodik-search-backend</name>
<description>Kodik search service for anyame</description>
<url />
<licenses>
@ -33,6 +33,8 @@
<retrofit.version>3.0.0</retrofit.version>
<spring-dotenv.version>4.0.0</spring-dotenv.version>
<springdoc-openapi-starter.version>2.8.9</springdoc-openapi-starter.version>
<spring-eureka-client.version>4.3.0</spring-eureka-client.version>
<logstash-logback-encoder.version>8.1</logstash-logback-encoder.version>
</properties>
<dependencies>
<dependency>
@ -60,6 +62,16 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-openapi-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>${spring-eureka-client.version}</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash-logback-encoder.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -13,6 +13,7 @@ import org.springframework.web.server.ResponseStatusException;
import com.backend.search.kodik.service.anyame_backend.api.KodikAPI;
import com.backend.search.kodik.service.anyame_backend.api.model.KodikResponse;
import com.backend.search.kodik.service.anyame_backend.component.KodikAPITokenProvider;
import com.backend.search.kodik.service.anyame_backend.service.KodikSearchFilterService;
import retrofit2.Response;
@ -21,10 +22,13 @@ public class SearchController {
Logger log = LoggerFactory.getLogger(SearchController.class);
private final KodikAPI kodikAPI;
private final KodikAPITokenProvider tokenProvider;
private final KodikSearchFilterService searchFilterService;
public SearchController(KodikAPI kodikAPI, KodikAPITokenProvider tokenProvider) {
public SearchController(KodikAPI kodikAPI, KodikAPITokenProvider tokenProvider,
KodikSearchFilterService searchFilterService) {
this.kodikAPI = kodikAPI;
this.tokenProvider = tokenProvider;
this.searchFilterService = searchFilterService;
}
@GetMapping("/search")
@ -36,8 +40,7 @@ public class SearchController {
response.message());
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "bad response, code: " + response.code());
}
log.info("search result {}", response.body());
return response.body();
return searchFilterService.filter(response.body());
} catch (IOException e) {
log.warn("i/o error", e);
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE, "i/o error");

View File

@ -0,0 +1,44 @@
package com.backend.search.kodik.service.anyame_backend.service;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.backend.search.kodik.service.anyame_backend.api.model.KodikResponse;
import com.backend.search.kodik.service.anyame_backend.api.model.KodikResponse.Result;
@Service
public class KodikSearchFilterService {
Logger log = LoggerFactory.getLogger(KodikSearchFilterService.class);
private static final List<String> ALLOWED_TYPES = Arrays.asList("anime-serial", "anime");
public KodikResponse filter(KodikResponse body) {
Set<String> seenIds = new HashSet<>();
List<Result> filteredResults = body.results.stream()
.filter(result -> ALLOWED_TYPES.contains(result.type))
.filter(result -> {
String identifier = identifier(result);
boolean updated = seenIds.add(identifier);
return updated;
})
.toList();
body.results = filteredResults;
return body;
}
public String identifier(Result result) {
List<String> identifiers = Arrays.asList(result.kinopoiskId,
result.imdbId,
result.shikimoriId,
result.worldartLink);
return identifiers.stream().filter(identifier -> identifier != null && !identifier.isBlank()).findFirst()
.orElse(result.id) + Integer.toString(result.lastSeason);
}
}

View File

@ -1,3 +1,3 @@
spring.application.name=anyame-backend
server.error.include-message=always
spring.application.name=anyame-kodik-search-backend
kodik.token=${KODIK_TOKEN}
eureka.client.serviceUrl.defaultZone: ${EUREKA_SCHEMA}://${EUREKA_HOST}/eureka/

View File

@ -0,0 +1,11 @@
<configuration>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>logstash:5044</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<root level="INFO">
<appender-ref ref="LOGSTASH" />
</root>
</configuration>