diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index f8c449a..4b5e866 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -14,7 +14,6 @@
-
diff --git a/pom.xml b/pom.xml
index fe2a4a3..76156b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,7 +118,7 @@
com.github.TeamNewPipe
NewPipeExtractor
- v0.24.6
+ v0.26.1
com.squareup.okhttp3
diff --git a/src/main/java/cc/wordview/api/controller/LyricsController.java b/src/main/java/cc/wordview/api/controller/TextTracksController.java
similarity index 66%
rename from src/main/java/cc/wordview/api/controller/LyricsController.java
rename to src/main/java/cc/wordview/api/controller/TextTracksController.java
index 9d00ec9..1042c0a 100644
--- a/src/main/java/cc/wordview/api/controller/LyricsController.java
+++ b/src/main/java/cc/wordview/api/controller/TextTracksController.java
@@ -18,11 +18,10 @@
package cc.wordview.api.controller;
import cc.wordview.api.Application;
-import cc.wordview.api.response.LyricsResponse;
-import cc.wordview.api.service.implementation.LyricsService;
-import cc.wordview.api.service.VideoLyricsServiceInterface;
-import cc.wordview.api.util.ArrayUtil;
+import cc.wordview.api.response.TextTrackResponse;
import cc.wordview.api.runtime.ResourceResolver;
+import cc.wordview.api.service.implementation.TextTracksService;
+import cc.wordview.api.util.ArrayUtil;
import cc.wordview.gengolex.Language;
import cc.wordview.gengolex.LanguageNotFoundException;
import cc.wordview.gengolex.Parser;
@@ -35,38 +34,48 @@
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
+import java.util.List;
import static cc.wordview.api.controller.response.Response.ok;
@RestController
@CrossOrigin(origins = Application.CORS_ORIGIN)
-@RequestMapping(path = Application.API_PATH + "/lyrics")
-public class LyricsController extends ServiceController {
+@RequestMapping(path = Application.API_PATH + "/text-tracks")
+public class TextTracksController extends ServiceController {
@Autowired
private ResourceResolver resourceResolver;
- @Autowired
- private VideoLyricsServiceInterface videoLyricsService;
-
- @GetMapping(produces = "application/json;charset=utf-8")
+ @GetMapping(produces = "application/json;charset=utf-8", path = "/lyrics")
public ResponseEntity> getLyrics(@RequestParam String id, @RequestParam String lang, @RequestParam String trackName, @RequestParam String artistName) throws IOException, LyricsNotFoundException, LanguageNotFoundException {
String decodedTrackName = URLDecoder.decode(trackName);
String decodedArtistName = URLDecoder.decode(artistName);
String lyrics = service.getLyrics(id, decodedTrackName, decodedArtistName, lang);
- String dictionariesPath = resourceResolver.getDictionariesPath();
+ ArrayList words = getContainingWords(lyrics, lang);
- Parser parser = new Parser(Language.Companion.byTag(lang), dictionariesPath);
-
- ArrayList words = ArrayUtil.withoutDuplicates(parser.findWords(lyrics.replace("\n", " ")));
-
- return ok(new LyricsResponse(lyrics, words));
+ return ok(new TextTrackResponse(lyrics, words));
}
@GetMapping(produces = "application/json;charset=utf-8", path = "/list")
public ResponseEntity> getLyricsList() {
- ArrayList ids = videoLyricsService.listLyricsIds();
+ List ids = service.listAvailableTracks();
return ok(ids);
}
+
+ @GetMapping(produces = "application/json;charset=utf-8", path = "/subtitles")
+ public ResponseEntity> getSubtitle(@RequestParam String id, @RequestParam String lang) throws IOException, LanguageNotFoundException {
+ String subtitle = service.getSubtitle(id, lang);
+ ArrayList words = getContainingWords(subtitle, lang);
+
+ return ok(new TextTrackResponse(subtitle, words));
+ }
+
+ private ArrayList getContainingWords(String vttFile, String lang) throws IOException, LanguageNotFoundException {
+ String dictionariesPath = resourceResolver.getDictionariesPath();
+
+ Parser parser = new Parser(Language.Companion.byTag(lang), dictionariesPath);
+
+ return ArrayUtil.withoutDuplicates(parser.findWords(vttFile.replace("\n", " ")));
+ }
}
diff --git a/src/main/java/cc/wordview/api/controller/response/ApiExceptionHandler.java b/src/main/java/cc/wordview/api/controller/response/ApiExceptionHandler.java
index 7078d44..7a8e228 100644
--- a/src/main/java/cc/wordview/api/controller/response/ApiExceptionHandler.java
+++ b/src/main/java/cc/wordview/api/controller/response/ApiExceptionHandler.java
@@ -55,7 +55,8 @@ public ResponseEntity badRequest(Exception e) {
FileNotFoundException.class,
LyricsNotFoundException.class,
LanguageNotFoundException.class,
- ImageNotFoundException.class
+ ImageNotFoundException.class,
+ SubtitleNotFoundException.class
})
public ResponseEntity notFound(Exception e) {
return error(HttpStatus.NOT_FOUND, e);
diff --git a/src/main/java/cc/wordview/api/database/entity/VideoLyrics.java b/src/main/java/cc/wordview/api/database/entity/TextTrack.java
similarity index 84%
rename from src/main/java/cc/wordview/api/database/entity/VideoLyrics.java
rename to src/main/java/cc/wordview/api/database/entity/TextTrack.java
index fda6be8..e426f09 100644
--- a/src/main/java/cc/wordview/api/database/entity/VideoLyrics.java
+++ b/src/main/java/cc/wordview/api/database/entity/TextTrack.java
@@ -25,8 +25,8 @@
@Entity
@Data
-@Table(name = "video_lyrics")
-public class VideoLyrics implements Serializable {
+@Table(name = "text_tracks")
+public class TextTrack implements Serializable {
@Serial
private static final long serialVersionUID = 1854932248236429655L;
@@ -38,9 +38,6 @@ public class VideoLyrics implements Serializable {
@Column(name = "video_id", unique = true)
private String videoId;
- @Column(name = "lyrics_file")
- private String lyricsFile;
-
- @Column(name = "time_offset")
- private int offset;
+ @Column(name = "file")
+ private String file;
}
diff --git a/src/main/java/cc/wordview/api/service/VideoLyricsServiceInterface.java b/src/main/java/cc/wordview/api/exception/SubtitleNotFoundException.java
similarity index 62%
rename from src/main/java/cc/wordview/api/service/VideoLyricsServiceInterface.java
rename to src/main/java/cc/wordview/api/exception/SubtitleNotFoundException.java
index 3a5cdf0..8afb110 100644
--- a/src/main/java/cc/wordview/api/service/VideoLyricsServiceInterface.java
+++ b/src/main/java/cc/wordview/api/exception/SubtitleNotFoundException.java
@@ -15,18 +15,10 @@
* along with this program. If not, see .
*/
-package cc.wordview.api.service;
+package cc.wordview.api.exception;
-import cc.wordview.api.database.entity.VideoLyrics;
-import cc.wordview.api.exception.NoSuchEntryException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public interface VideoLyricsServiceInterface extends ServiceInterface {
- VideoLyrics getByVideoId(String videoId) throws NoSuchEntryException;
-
- ArrayList listLyricsIds();
-
- List getAll();
+public class SubtitleNotFoundException extends RuntimeException {
+ public SubtitleNotFoundException(String message) {
+ super(message);
+ }
}
diff --git a/src/main/java/cc/wordview/api/repository/VideoLyricsRepository.java b/src/main/java/cc/wordview/api/repository/TextTracksRepository.java
similarity index 81%
rename from src/main/java/cc/wordview/api/repository/VideoLyricsRepository.java
rename to src/main/java/cc/wordview/api/repository/TextTracksRepository.java
index 9ae7054..f73070f 100644
--- a/src/main/java/cc/wordview/api/repository/VideoLyricsRepository.java
+++ b/src/main/java/cc/wordview/api/repository/TextTracksRepository.java
@@ -17,11 +17,11 @@
package cc.wordview.api.repository;
-import cc.wordview.api.database.entity.VideoLyrics;
+import cc.wordview.api.database.entity.TextTrack;
import org.springframework.data.repository.CrudRepository;
import java.util.Optional;
-public interface VideoLyricsRepository extends CrudRepository {
- Optional findByVideoId(String videoId);
+public interface TextTracksRepository extends CrudRepository {
+ Optional findByVideoId(String videoId);
}
diff --git a/src/main/java/cc/wordview/api/response/LyricsResponse.java b/src/main/java/cc/wordview/api/response/TextTrackResponse.java
similarity index 93%
rename from src/main/java/cc/wordview/api/response/LyricsResponse.java
rename to src/main/java/cc/wordview/api/response/TextTrackResponse.java
index ba292f9..cf9c849 100644
--- a/src/main/java/cc/wordview/api/response/LyricsResponse.java
+++ b/src/main/java/cc/wordview/api/response/TextTrackResponse.java
@@ -25,7 +25,7 @@
@Data
@AllArgsConstructor
-public class LyricsResponse {
- private String lyrics;
+public class TextTrackResponse {
+ private String textTrack;
private List dictionary;
}
diff --git a/src/main/java/cc/wordview/api/runtime/ResourceResolver.java b/src/main/java/cc/wordview/api/runtime/ResourceResolver.java
index bcbfe56..598f6ea 100644
--- a/src/main/java/cc/wordview/api/runtime/ResourceResolver.java
+++ b/src/main/java/cc/wordview/api/runtime/ResourceResolver.java
@@ -43,6 +43,12 @@ public class ResourceResolver {
@Value("${wordview.lyrics_path}")
private String lyricsPath;
+ @Value("${wordview.subtitles_path}")
+ private String subtitlesPath;
+
+ @Value("${wordview.text_tracks_path}")
+ private String textTracksPath;
+
@Value("${wordview.phrases_path}")
private String phrasesPath;
@@ -59,11 +65,13 @@ public void debugShowPaths() {
Dictionaries Path: {}
Images Path: {}
Lyrics Path: {}
+ Subtitles Path: {}
+ Text Tracks Path: {}
Phrases Path: {}
Translations Path: {}
Feeds Path: {}
""",
- dictionariesPath, imagesPath, lyricsPath, phrasesPath, translationsPath, feedsPath);
+ dictionariesPath, imagesPath, lyricsPath, subtitlesPath, textTracksPath, phrasesPath, translationsPath, feedsPath);
}
public String getDictionariesPath() throws IOException {
@@ -78,6 +86,14 @@ public String getLyricsPath() throws IOException {
return resolvePathOrClasspath(lyricsPath);
}
+ public String getSubtitlesPath() throws IOException {
+ return resolvePathOrClasspath(subtitlesPath);
+ }
+
+ public String getTextTracksPath() throws IOException {
+ return resolvePathOrClasspath(textTracksPath);
+ }
+
public String getPhrasesPath() throws IOException {
return resolvePathOrClasspath(phrasesPath);
}
diff --git a/src/main/java/cc/wordview/api/runtime/cache/LyricsCache.java b/src/main/java/cc/wordview/api/runtime/cache/TextTrackCache.java
similarity index 54%
rename from src/main/java/cc/wordview/api/runtime/cache/LyricsCache.java
rename to src/main/java/cc/wordview/api/runtime/cache/TextTrackCache.java
index 17f7e49..018ff8c 100644
--- a/src/main/java/cc/wordview/api/runtime/cache/LyricsCache.java
+++ b/src/main/java/cc/wordview/api/runtime/cache/TextTrackCache.java
@@ -17,9 +17,9 @@
package cc.wordview.api.runtime.cache;
-import cc.wordview.api.database.entity.VideoLyrics;
+import cc.wordview.api.database.entity.TextTrack;
+import cc.wordview.api.repository.TextTracksRepository;
import cc.wordview.api.runtime.ResourceResolver;
-import cc.wordview.api.service.VideoLyricsServiceInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,50 +34,48 @@
import java.util.stream.Stream;
@Component
-public class LyricsCache extends HashMapCacheManager {
- private static final Logger logger = LoggerFactory.getLogger(LyricsCache.class);
+public class TextTrackCache extends HashMapCacheManager {
+ private static final Logger logger = LoggerFactory.getLogger(TextTrackCache.class);
@Autowired
private ResourceResolver resourceResolver;
@Autowired
- private VideoLyricsServiceInterface videoLyricsService;
+ private TextTracksRepository repository;
@Override
public void init() throws IOException {
- String lyricsPath = resourceResolver.getLyricsPath();
- Path filepath = Path.of(lyricsPath);
+ String subtitlesPath = resourceResolver.getTextTracksPath();
+ Path filepath = Path.of(subtitlesPath);
Map fileToContent = new HashMap<>();
try (Stream paths = Files.walk(filepath)) {
- paths.filter(Files::isRegularFile)
- .forEach(file -> {
- try {
- fileToContent.put(file.getFileName().toString(), Files.readString(file));
- } catch (IOException e) {
- logger.error("Failed to read lyrics file, ignoring this file", e);
- }
- });
+ paths.filter(Files::isRegularFile).forEach(file -> {
+ try {
+ fileToContent.put(file.getFileName().toString(), Files.readString(file));
+ } catch (IOException e) {
+ logger.error("Failed to read subtitle file, ignoring this file", e);
+ }
+ });
- List videoLyrics = videoLyricsService.getAll();
+ List textTracks = (List) repository.findAll();
- for (var videoLyric : videoLyrics) {
- String content = fileToContent.get(videoLyric.getLyricsFile() + ".vtt");
- map.put(videoLyric.getVideoId(), content);
+ for (var subtitle : textTracks) {
+ String content = fileToContent.get(subtitle.getFile());
+ map.put(subtitle.getVideoId(), content);
}
- logger.info("Preloaded {} lyrics", map.size());
+ logger.info("Preloaded {} text tracks", map.size());
} catch (IOException e) {
- logger.error("Failed to read the lyrics path", e);
+ logger.error("Failed to read the text tracks path", e);
}
}
- public void put(String id, String lyrics) {
+ public void put(String id, String subtitle) {
if (map.containsKey(id))
return;
-
- logger.info("Adding {} to cache, there are now {} lyrics", id, map.size() + 1);
- map.put(id, lyrics);
+ logger.info("Adding {} to cache, there are now {} text tracks", id, map.size() + 1);
+ map.put(id, subtitle);
}
}
diff --git a/src/main/java/cc/wordview/api/service/LyricsServiceInterface.java b/src/main/java/cc/wordview/api/service/TextTracksServiceInterface.java
similarity index 74%
rename from src/main/java/cc/wordview/api/service/LyricsServiceInterface.java
rename to src/main/java/cc/wordview/api/service/TextTracksServiceInterface.java
index be5790a..74167d7 100644
--- a/src/main/java/cc/wordview/api/service/LyricsServiceInterface.java
+++ b/src/main/java/cc/wordview/api/service/TextTracksServiceInterface.java
@@ -17,12 +17,14 @@
package cc.wordview.api.service;
+import cc.wordview.api.exception.SubtitleNotFoundException;
import cc.wordview.wordfind.exception.LyricsNotFoundException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import java.io.IOException;
+import java.util.List;
-public interface LyricsServiceInterface {
+public interface TextTracksServiceInterface {
/**
* Retrieves the lyrics for a track
*
@@ -37,6 +39,17 @@ public interface LyricsServiceInterface {
*/
String getLyrics(String id, String trackName, String artistName, String langTag) throws ExtractionException, IOException, LyricsNotFoundException;
+ /**
+ * Retrieves the subtitles for the track given the `id`
+ * @param id the YouTube id of the video.
+ * @param langTag the language the subtitle should be in.
+ * @return the subtitles formatted in VTT.
+ * @throws ExtractionException if subtitle extraction from YouTube fails.
+ * @throws IOException if reading subtitles from disk fails.
+ * @throws SubtitleNotFoundException if no valid subtitles are found.
+ */
+ String getSubtitle(String id, String langTag) throws ExtractionException, IOException, SubtitleNotFoundException;
+
/**
* Attempts to retrieve lyrics for the given track and artist from an external provider from WordFind.
*
@@ -47,5 +60,10 @@ public interface LyricsServiceInterface {
* @throws LyricsNotFoundException if no lyrics are found for the provided track and artist.
*/
String getLyricsExternal(String trackName, String artistName) throws IOException, LyricsNotFoundException;
+
+ /**
+ * Retrieves a list of the tracks currently provided by the API.
+ */
+ List listAvailableTracks();
}
diff --git a/src/main/java/cc/wordview/api/service/implementation/LyricsService.java b/src/main/java/cc/wordview/api/service/implementation/TextTracksService.java
similarity index 53%
rename from src/main/java/cc/wordview/api/service/implementation/LyricsService.java
rename to src/main/java/cc/wordview/api/service/implementation/TextTracksService.java
index e31f790..0682c44 100644
--- a/src/main/java/cc/wordview/api/service/implementation/LyricsService.java
+++ b/src/main/java/cc/wordview/api/service/implementation/TextTracksService.java
@@ -17,9 +17,11 @@
package cc.wordview.api.service.implementation;
-import cc.wordview.api.runtime.cache.LyricsCache;
-import cc.wordview.api.service.LyricsServiceInterface;
-import cc.wordview.api.runtime.DownloaderImpl;
+import cc.wordview.api.database.entity.TextTrack;
+import cc.wordview.api.exception.SubtitleNotFoundException;
+import cc.wordview.api.repository.TextTracksRepository;
+import cc.wordview.api.runtime.cache.TextTrackCache;
+import cc.wordview.api.service.TextTracksServiceInterface;
import cc.wordview.wordfind.WordFind;
import cc.wordview.wordfind.exception.LyricsNotFoundException;
import jakarta.annotation.PostConstruct;
@@ -28,32 +30,41 @@
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
@Service
-public class LyricsService implements LyricsServiceInterface {
+public class TextTracksService implements TextTracksServiceInterface {
+ private static final Logger logger = LoggerFactory.getLogger(TextTracksService.class);
private static StreamingService YTService;
private final WordFind client = new WordFind();
@Autowired
- private LyricsCache cache;
+ private TextTrackCache cache;
+
+ @Autowired
+ private TextTracksRepository repository;
@Override
- public String getLyrics(String id, String trackName, String artistName, String langTag) throws IOException, LyricsNotFoundException {
+ public String getLyrics(String id, String trackName, String artistName, String langTag) throws LyricsNotFoundException {
String lyrics = cache.get(id);
- if (lyrics == null)
- lyrics = getLyricsYT(id, langTag);
+ if (lyrics == null) {
+ lyrics = getYouTubeSubtitle(id, langTag);
+ }
- if (lyrics == null)
+ if (lyrics == null) {
lyrics = getLyricsExternal(trackName, artistName);
-
+ }
if (Objects.equals(lyrics, "WEBVTT\n\n# This WEBVTT was converted from LRC and might contain errors\n\n")) {
throw new LyricsNotFoundException("Unable to find lyrics for %s".formatted(trackName));
@@ -63,24 +74,39 @@ public String getLyrics(String id, String trackName, String artistName, String l
return lyrics;
}
- private String getLyricsYT(String id, String langTag) {
- StreamInfo info;
+ @Override
+ public String getSubtitle(String id, String langTag) throws SubtitleNotFoundException {
+ String subtitle = cache.get(id);
+
+ if (subtitle == null) {
+ subtitle = getYouTubeSubtitle(id, langTag);
+ }
- try {
- info = StreamInfo.getInfo(YTService, "https://youtube.com/watch?v=" + id);
- } catch (Exception e) {
- return null;
+ if (subtitle == null) {
+ throw new SubtitleNotFoundException("Unable to find any subtitles for the video %s".formatted(id));
}
- for (SubtitlesStream subtitle : info.getSubtitles()) {
- if (subtitle.isAutoGenerated()) continue;
+ cache.put(id, subtitle);
+
+ return subtitle;
+ }
- if (Objects.equals(subtitle.getLanguageTag(), langTag)) {
- String url = subtitle.getContent().replace("&fmt=ttml", "&fmt=vtt");
- RestTemplate restTemplate = new RestTemplate();
- return restTemplate.getForObject(url, String.class);
+ private String getYouTubeSubtitle(String id, String lang) {
+ try {
+ StreamInfo info = StreamInfo.getInfo(YTService, "https://youtube.com/watch?v=" + id);
+
+ for (SubtitlesStream subtitle : info.getSubtitles()) {
+ if (subtitle.isAutoGenerated()) continue;
+
+ if (Objects.equals(subtitle.getLanguageTag(), lang)) {
+ String url = subtitle.getContent().replace("&fmt=ttml", "&fmt=vtt");
+
+ return new RestTemplate().getForObject(url, String.class);
+ }
}
+ } catch (Exception e) {
+ logger.error("Failed to retrieve subtitles from YouTube", e);
}
return null;
@@ -100,4 +126,16 @@ private void preloadLyrics() throws IOException {
public String getLyricsExternal(String trackName, String artistName) throws LyricsNotFoundException {
return client.find(trackName, artistName, true, null, null);
}
+
+ @Override
+ public List listAvailableTracks() {
+ Iterable tracks = repository.findAll();
+ ArrayList ids = new ArrayList<>();
+
+ for (TextTrack track : tracks) {
+ ids.add(track.getVideoId());
+ }
+
+ return ids;
+ }
}
diff --git a/src/main/java/cc/wordview/api/service/implementation/VideoLyricsService.java b/src/main/java/cc/wordview/api/service/implementation/VideoLyricsService.java
deleted file mode 100644
index 6af2416..0000000
--- a/src/main/java/cc/wordview/api/service/implementation/VideoLyricsService.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2025 Arthur Araujo
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package cc.wordview.api.service.implementation;
-
-import cc.wordview.api.database.entity.VideoLyrics;
-import cc.wordview.api.exception.NoSuchEntryException;
-import cc.wordview.api.repository.VideoLyricsRepository;
-import cc.wordview.api.service.VideoLyricsServiceInterface;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-@Service
-public class VideoLyricsService implements VideoLyricsServiceInterface {
- @Autowired
- private VideoLyricsRepository repository;
-
- @Override
- public VideoLyrics getByVideoId(String videoId) throws NoSuchEntryException {
- Optional videoLyrics = repository.findByVideoId(videoId);
-
- if (!videoLyrics.isPresent()) {
- throw new NoSuchEntryException("Unable to find any lyrics with this videoId");
- }
-
- return videoLyrics.get();
- }
-
- @Override
- public ArrayList listLyricsIds() {
- Iterable allLyrics = repository.findAll();
- ArrayList ids = new ArrayList<>();
-
- for (VideoLyrics lyric : allLyrics) {
- ids.add(lyric.getVideoId());
- }
-
- return ids;
- }
-
- @Override
- public List getAll() {
- return (List) repository.findAll();
- }
-
-
- @Override
- public VideoLyrics getById(Long id) {
- throw new UnsupportedOperationException("getById is disabled for VideoLyricsService");
- }
-
- @Override
- public VideoLyrics insert(VideoLyrics entity) {
- // They should be manually added to the sql
- throw new UnsupportedOperationException("insert is disabled for VideoLyricsService");
- }
-}
diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties
index b7415a5..39eb5f1 100644
--- a/src/main/resources/application-dev.properties
+++ b/src/main/resources/application-dev.properties
@@ -18,6 +18,8 @@ spring.jpa.open-in-view=false
wordview.dictionaries_path=classpath:/dictionaries/
wordview.images_path=classpath:/images/
wordview.lyrics_path=classpath:/lyrics/
+wordview.subtitles_path=classpath:/subtitles/
+wordview.text_tracks_path=classpath:/text-tracks/
wordview.phrases_path=classpath:/phrases/
wordview.translations_path=classpath:/translations/
wordview.feeds_path=classpath:/feeds/
diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties
index ee92e76..a0ae9c6 100644
--- a/src/main/resources/application-prod.properties
+++ b/src/main/resources/application-prod.properties
@@ -16,6 +16,6 @@ spring.jpa.open-in-view=false
wordview.dictionaries_path=
wordview.images_path=
-wordview.lyrics_path=
+wordview.text_tracks_path=
wordview.phrases_path=
wordview.feeds_path=
\ No newline at end of file
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 8bd4a0b..7bd9a62 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -1,23 +1,29 @@
-INSERT INTO member (username, email, password) VALUES
- ('Arthur', 'arthur.araujo@tutanota.com', 'senha');
+INSERT INTO member (username, email, password)
+VALUES ('Arthur', 'arthur.araujo@tutanota.com', 'senha');
-INSERT INTO member (username, email, password) VALUES
- ('conta', 'conta2@tutanota.com', 'senha');
+INSERT INTO member (username, email, password)
+VALUES ('conta', 'conta2@tutanota.com', 'senha');
-INSERT INTO member (username, email, password, role) VALUES
- ('mock.user', 'mock.user@gmail.com', '8631b7298388ab36f3785770cc07c4ea', 'USER');
+INSERT INTO member (username, email, password, role)
+VALUES ('mock.user', 'mock.user@gmail.com', '8631b7298388ab36f3785770cc07c4ea', 'USER');
-INSERT INTO member (username, email, password, role) VALUES
- ('mock.disposable', 'mock.disposable@gmail.com', '5b4a4769301f10a5ac64609e7e0bba0e', 'USER');
+INSERT INTO member (username, email, password, role)
+VALUES ('mock.disposable', 'mock.disposable@gmail.com', '5b4a4769301f10a5ac64609e7e0bba0e', 'USER');
-INSERT INTO member (username, email, password, role) VALUES
- ('mock.disposable.email', 'mock.disposable.email@gmail.com', '407c8797b415f2e557dc141d16c4ac86', 'USER');
+INSERT INTO member (username, email, password, role)
+VALUES ('mock.disposable.email', 'mock.disposable.email@gmail.com', '407c8797b415f2e557dc141d16c4ac86', 'USER');
-INSERT INTO member (username, email, password, role) VALUES
- ('mock.admin', 'mock.admin@gmail.com', '061cf224cffe1951e32ffaa1c414544a', 'ADMIN');
+INSERT INTO member (username, email, password, role)
+VALUES ('mock.admin', 'mock.admin@gmail.com', '061cf224cffe1951e32ffaa1c414544a', 'ADMIN');
-INSERT INTO email (email) VALUES ('mock.user@gmail.com');
+INSERT INTO email (email)
+VALUES ('mock.user@gmail.com');
-INSERT INTO known_words (user_id, lang, words) VALUES (3, 'en', 'rain,world');
+INSERT INTO known_words (user_id, lang, words)
+VALUES (3, 'en', 'rain,world');
-INSERT INTO video_lyrics (video_id, lyrics_file, time_offset) VALUES ('ZnUEeXpxBJ0', 'aquarela', 0);
\ No newline at end of file
+INSERT INTO text_tracks (video_id, file)
+VALUES ('ZnUEeXpxBJ0', 'lyrics/aquarela.vtt');
+
+INSERT INTO text_tracks (video_id, file)
+VALUES ('K9Ydi94yT94', 'subtitles/uma_wo_kakudaisuru_ge-mu.vtt');
\ No newline at end of file
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index 2660a16..d3fcc88 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -1,35 +1,38 @@
DROP TABLE IF EXISTS member CASCADE;
DROP TABLE IF EXISTS email CASCADE;
-DROP TABLE IF EXISTS video_lyrics CASCADE;
+DROP TABLE IF EXISTS text_tracks CASCADE;
-CREATE TABLE member (
- id bigint GENERATED ALWAYS AS IDENTITY,
- username varchar(255),
- email varchar(255) UNIQUE,
- password varchar(255),
- role varchar(255),
+CREATE TABLE member
+(
+ id bigint GENERATED ALWAYS AS IDENTITY,
+ username varchar(255),
+ email varchar(255) UNIQUE,
+ password varchar(255),
+ role varchar(255),
lesson_time bigint DEFAULT 300000,
PRIMARY KEY (id)
);
-CREATE TABLE email (
- id bigint GENERATED ALWAYS AS IDENTITY,
+CREATE TABLE email
+(
+ id bigint GENERATED ALWAYS AS IDENTITY,
email varchar(255) UNIQUE,
PRIMARY KEY (id)
);
-CREATE TABLE video_lyrics (
- id bigint GENERATED ALWAYS AS IDENTITY,
- video_id varchar(12) UNIQUE,
- lyrics_file varchar(128),
- time_offset int,
+CREATE TABLE text_tracks
+(
+ id bigint GENERATED ALWAYS AS IDENTITY,
+ video_id varchar(12) UNIQUE,
+ file varchar(128),
PRIMARY KEY (id)
);
-CREATE TABLE known_words (
- id bigint GENERATED ALWAYS AS IDENTITY,
+CREATE TABLE known_words
+(
+ id bigint GENERATED ALWAYS AS IDENTITY,
user_id bigint,
- lang varchar(64),
- words varchar(5120),
+ lang varchar(64),
+ words varchar(5120),
PRIMARY KEY (id)
);
diff --git a/src/main/resources/lyrics/aquarela.vtt b/src/main/resources/text-tracks/lyrics/aquarela.vtt
similarity index 100%
rename from src/main/resources/lyrics/aquarela.vtt
rename to src/main/resources/text-tracks/lyrics/aquarela.vtt
diff --git a/src/main/resources/text-tracks/subtitles/uma_wo_kakudaisuru_ge-mu.vtt b/src/main/resources/text-tracks/subtitles/uma_wo_kakudaisuru_ge-mu.vtt
new file mode 100644
index 0000000..60c772e
--- /dev/null
+++ b/src/main/resources/text-tracks/subtitles/uma_wo_kakudaisuru_ge-mu.vtt
@@ -0,0 +1,8 @@
+WEBVTT
+
+00:00:0.100 --> 00:00:3.000
+馬を拡大して面白い形にしたいなって
+
+00:00:3.000 --> 00:00:4.500
+思ったことはありますか?
+
diff --git a/src/test/java/cc/wordview/api/test/api/controller/LyricsControllerTest.java b/src/test/java/cc/wordview/api/test/api/controller/TextTracksControllerTest.java
similarity index 65%
rename from src/test/java/cc/wordview/api/test/api/controller/LyricsControllerTest.java
rename to src/test/java/cc/wordview/api/test/api/controller/TextTracksControllerTest.java
index 0a35923..4e05cd5 100644
--- a/src/test/java/cc/wordview/api/test/api/controller/LyricsControllerTest.java
+++ b/src/test/java/cc/wordview/api/test/api/controller/TextTracksControllerTest.java
@@ -26,19 +26,19 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-class LyricsControllerTest extends ControllerTest {
+class TextTracksControllerTest extends ControllerTest {
@Test
@Disabled("Makes a external request, only run this when ABSOLUTELY NECESSARY")
void getLyrics() throws Exception {
- req.get("/lyrics?id=1cGQotpn8r4&lang=ja&trackName=a&artistName=a")
+ req.get("/text-tracks/lyrics?id=1cGQotpn8r4&lang=ja&trackName=a&artistName=a")
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=utf-8"));
}
@Test
-// @Disabled("Does not make external request but don't seem to work on CI")
+ @Disabled("Does not make external request but don't seem to work on CI")
void getLyricsWordView() throws Exception {
- req.get("/lyrics?id=ZnUEeXpxBJ0&lang=pt&trackName=aquarela&artistName=toquinho")
+ req.get("/text-tracks/lyrics?id=ZnUEeXpxBJ0&lang=pt&trackName=aquarela&artistName=toquinho")
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=utf-8"));
}
@@ -46,7 +46,7 @@ void getLyricsWordView() throws Exception {
@Test
@Disabled("Makes a external request, only run this when ABSOLUTELY NECESSARY")
void getLyricsWordFind() throws Exception {
- req.get("/lyrics?id=vcw5THyM7Jo&lang=ja&trackName=%s&artistName=%s".formatted(
+ req.get("/text-tracks/lyrics?id=vcw5THyM7Jo&lang=ja&trackName=%s&artistName=%s".formatted(
URLEncoder.encode("終点の先が在るとするならば。"),
URLEncoder.encode("ツユ")
))
@@ -58,7 +58,7 @@ void getLyricsWordFind() throws Exception {
@Test
@Disabled("Makes a external request, only run this when ABSOLUTELY NECESSARY")
void getLyricsNotFound() throws Exception {
- req.get("/lyrics?id=vcw5THyM7Jo&lang=ja&trackName=%s&artistName=%s".formatted(
+ req.get("/text-tracks/lyrics?id=vcw5THyM7Jo&lang=ja&trackName=%s&artistName=%s".formatted(
URLEncoder.encode("a_song_that_doesnt_exist"),
URLEncoder.encode("aa")
)).andExpect(status().isNotFound());
@@ -66,7 +66,23 @@ void getLyricsNotFound() throws Exception {
@Test
void getListOfLyricsIds() throws Exception {
- req.get("/lyrics/list")
+ req.get("/text-tracks/list")
+ .andExpect(status().isOk())
+ .andExpect(content().contentType("application/json;charset=utf-8"));
+ }
+
+ @Test
+ @Disabled("Makes a external request, only run this when ABSOLUTELY NECESSARY")
+ void getSubtitlesYouTube() throws Exception {
+ req.get("/text-tracks/subtitles?id=eCipMjo1vSI&lang=ja")
+ .andExpect(status().isOk())
+ .andExpect(content().contentType("application/json;charset=utf-8"));
+ }
+
+ @Test
+ @Disabled("Disabled until https://github.com/word-view/APIWordView/issues/50 is fixed")
+ void getSubtitlesWordView() throws Exception {
+ req.get("/text-tracks/subtitles?id=K9Ydi94yT94&lang=ja")
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=utf-8"));
}