Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
<dependency>
<groupId>com.github.TeamNewPipe</groupId>
<artifactId>NewPipeExtractor</artifactId>
<version>v0.24.6</version>
<version>v0.26.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<LyricsService> {
@RequestMapping(path = Application.API_PATH + "/text-tracks")
public class TextTracksController extends ServiceController<TextTracksService> {
@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<Word> words = getContainingWords(lyrics, lang);

Parser parser = new Parser(Language.Companion.byTag(lang), dictionariesPath);

ArrayList<Word> 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<String> ids = videoLyricsService.listLyricsIds();
List<String> 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<Word> words = getContainingWords(subtitle, lang);

return ok(new TextTrackResponse(subtitle, words));
}

private ArrayList<Word> 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", " ")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public ResponseEntity<ApiError> badRequest(Exception e) {
FileNotFoundException.class,
LyricsNotFoundException.class,
LanguageNotFoundException.class,
ImageNotFoundException.class
ImageNotFoundException.class,
SubtitleNotFoundException.class
})
public ResponseEntity<ApiError> notFound(Exception e) {
return error(HttpStatus.NOT_FOUND, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

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> {
VideoLyrics getByVideoId(String videoId) throws NoSuchEntryException;

ArrayList<String> listLyricsIds();

List<VideoLyrics> getAll();
public class SubtitleNotFoundException extends RuntimeException {
public SubtitleNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<VideoLyrics, Long> {
Optional<VideoLyrics> findByVideoId(String videoId);
public interface TextTracksRepository extends CrudRepository<TextTrack, Long> {
Optional<TextTrack> findByVideoId(String videoId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

@Data
@AllArgsConstructor
public class LyricsResponse {
private String lyrics;
public class TextTrackResponse {
private String textTrack;
private List<Word> dictionary;
}
18 changes: 17 additions & 1 deletion src/main/java/cc/wordview/api/runtime/ResourceResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 {
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,50 +34,48 @@
import java.util.stream.Stream;

@Component
public class LyricsCache extends HashMapCacheManager<String> {
private static final Logger logger = LoggerFactory.getLogger(LyricsCache.class);
public class TextTrackCache extends HashMapCacheManager<String> {
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<String, String> fileToContent = new HashMap<>();

try (Stream<Path> 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> videoLyrics = videoLyricsService.getAll();
List<TextTrack> textTracks = (List<TextTrack>) 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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.
*
Expand All @@ -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<String> listAvailableTracks();
}

Loading
Loading