diff --git a/src/main/java/com/akshathsaipittala/streamspace/indexer/MediaIndexer.java b/src/main/java/com/akshathsaipittala/streamspace/indexer/MediaIndexer.java index 30bf8fc..466a424 100644 --- a/src/main/java/com/akshathsaipittala/streamspace/indexer/MediaIndexer.java +++ b/src/main/java/com/akshathsaipittala/streamspace/indexer/MediaIndexer.java @@ -29,7 +29,6 @@ import java.util.function.Function; import java.util.function.UnaryOperator; -@Async @Slf4j @Service @RequiredArgsConstructor @@ -41,6 +40,7 @@ public class MediaIndexer { final MovieRepository movieRepository; final MusicRepository musicRepository; + @Async public void indexMovie(TorrentFile file, String torrentName, String fileName, TorrentId torrentId) { log.info("FileName {}", fileName); log.info("TorrentName {}", torrentName); @@ -70,6 +70,7 @@ public void indexMovie(TorrentFile file, String torrentName, String fileName, To } + @Async public void indexMusic(TorrentFile file, String torrentName, String fileName, TorrentId torrentId) { log.info("FileName {}", fileName); log.info("TorrentName {}", torrentName); @@ -89,40 +90,25 @@ public void indexMusic(TorrentFile file, String torrentName, String fileName, To /** * Concurrent indexer */ - public void indexLocalMedia(String... locations) throws IOException { - findLocalMediaFiles(locations) - .thenApply(paths -> { - List musicPaths = paths.parallelStream() - .filter(path -> path.toString().endsWith(".mp3") || path.toString().endsWith(".flac")) - .toList(); - - List moviePaths = paths.parallelStream() - .filter(path -> path.toString().endsWith(".mp4") || path.toString().endsWith(".mkv") || path.toString().endsWith(".avi") || path.toString().endsWith(".mpeg")) - .toList(); - - List finalMovies; - List finalSongs; + @Async + public CompletableFuture indexLocalMedia(String... locations) throws IOException { + return findLocalMediaFiles(locations) + .thenCompose(paths -> { + List musicPaths = filterPaths(paths, ".mp3", ".flac"); + List moviePaths = filterPaths(paths, ".mp4", ".mkv", ".avi", ".mpeg"); + try { - finalMovies = createMovieEntities(moviePaths); - finalSongs = createMusicEntities(musicPaths); + List finalMovies = createMovieEntities(moviePaths); + List finalSongs = createMusicEntities(musicPaths); + + CompletableFuture moviesFuture = saveMoviesAsync(finalMovies); + CompletableFuture musicFuture = saveMusicAsync(finalSongs); + + return CompletableFuture.allOf(moviesFuture, musicFuture); } catch (IOException e) { - throw new RuntimeException(e); + log.error("Error creating media entities", e); + return CompletableFuture.failedFuture(e); } - - // Save entities to the database asynchronously - CompletableFuture moviesFuture = CompletableFuture.runAsync(() -> - finalMovies.stream() - .filter(movie -> !movieRepository.existsByContentId(movie.getContentId())) - .forEach(movieRepository::save)) - .thenRun(() -> log.info("Finished Indexing Movies")); - CompletableFuture musicFuture = CompletableFuture.runAsync(() -> - finalSongs.stream() - .filter(song -> !musicRepository.existsByContentId(song.getContentId())) - .forEach(musicRepository::save)) - .thenRun(() -> log.info("Finished Indexing Music")); - - // Return a new CompletableFuture that is completed when both of the provided CompletableFutures complete - return CompletableFuture.allOf(moviesFuture, musicFuture); }) .exceptionally(throwable -> { log.error("Error indexing media", throwable); @@ -130,35 +116,63 @@ public void indexLocalMedia(String... locations) throws IOException { }); } - private CompletableFuture> findLocalMediaFiles(String... locations) throws IOException { + private CompletableFuture> findLocalMediaFiles(String... locations) { final String pattern = "glob:**/*.{mp4,mpeg,mp3,mkv,flac}"; List matchingPaths = new ArrayList<>(); PathMatcher matcher = FileSystems.getDefault().getPathMatcher(pattern); for (String location : locations) { - - Path start = Paths.get(location); - - if (Files.exists(start)) { - - Files.walkFileTree(start, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { - if (matcher.matches(path)) { - matchingPaths.add(path); + try { + Path start = Paths.get(location); + if (Files.exists(start)) { + Files.walkFileTree(start, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { + if (matcher.matches(path)) { + matchingPaths.add(path); + } + return FileVisitResult.CONTINUE; } - return FileVisitResult.CONTINUE; - } - }); - + }); + } + } catch (IOException e) { + log.error("Error finding personal media files in location: {}", location, e); } - } return CompletableFuture.completedFuture(matchingPaths); } + private List filterPaths(List paths, String... extensions) { + return paths.parallelStream() + .filter(path -> { + String pathString = path.toString().toLowerCase(); + for (String ext : extensions) { + if (pathString.endsWith(ext)) { + return true; + } + } + return false; + }) + .toList(); + } + + private CompletableFuture saveMoviesAsync(List movies) { + return CompletableFuture.runAsync(() -> + movies.stream() + .filter(movie -> !movieRepository.existsByContentId(movie.getContentId())) + .forEach(movieRepository::save)) + .thenRun(() -> log.info("Finished Indexing Movies")); + } + + private CompletableFuture saveMusicAsync(List songs) { + return CompletableFuture.runAsync(() -> + songs.stream() + .filter(song -> !musicRepository.existsByContentId(song.getContentId())) + .forEach(musicRepository::save)) + .thenRun(() -> log.info("Finished Indexing Music")); + } private List createMovieEntities(List paths) throws IOException { diff --git a/src/main/java/com/akshathsaipittala/streamspace/services/BackgroundServices.java b/src/main/java/com/akshathsaipittala/streamspace/services/BackgroundServices.java index e19a292..c78f3b7 100644 --- a/src/main/java/com/akshathsaipittala/streamspace/services/BackgroundServices.java +++ b/src/main/java/com/akshathsaipittala/streamspace/services/BackgroundServices.java @@ -41,23 +41,23 @@ public class BackgroundServices { @Autowired private TorrentDownloadService torrentDownloadService; + @Async @EventListener(ApplicationReadyEvent.class) public void onApplicationReadyEvent() { - - Thread.startVirtualThread(() -> { - try { - log.info("Indexing Local Media"); - mediaIndexer.indexLocalMedia( - runtimeHelper.getMediaFolders().get(CONTENTTYPE.VIDEO), - runtimeHelper.getMediaFolders().get(CONTENTTYPE.AUDIO) - ); - startBackgroundDownloads(); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - + try { + log.info("Indexing Local Media"); + mediaIndexer.indexLocalMedia( + runtimeHelper.getMediaFolders().get(CONTENTTYPE.VIDEO), + runtimeHelper.getMediaFolders().get(CONTENTTYPE.AUDIO) + ).thenRunAsync(this::startBackgroundDownloads) + .exceptionally(throwable -> { + log.error("Error during media indexing or starting background downloads", throwable); + return null; + }); + } catch (IOException e) { + log.error("Error indexing local media", e); + } } @Async