Externalized thumbnail generation from controller; added insert to db

This commit is contained in:
itdominator 2023-09-21 20:49:24 -05:00
parent dddf1d7370
commit 366f1f7e69
8 changed files with 102 additions and 54 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
# Compiled class file # Compiled class file
*.class *.class
.vscode .vscode
database.db
# Log file # Log file
*.log *.log

View File

@ -2,10 +2,12 @@ package com.itdominator.api;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@SpringBootApplication @SpringBootApplication
@ComponentScan("com.itdominator.api")
@Configuration @Configuration
public class ThumbnailApiApplication { public class ThumbnailApiApplication {

View File

@ -2,16 +2,13 @@ package com.itdominator.api.controller;
import java.io.IOException; import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -23,7 +20,9 @@ import org.springframework.web.bind.annotation.RestController;
import com.itdominator.api.dto.ThumbnailDto; import com.itdominator.api.dto.ThumbnailDto;
import com.itdominator.api.dto.ThumbnailSearchCriteria; import com.itdominator.api.dto.ThumbnailSearchCriteria;
import com.itdominator.api.entities.Thumbnails;
import com.itdominator.api.services.ThumbnailerService; import com.itdominator.api.services.ThumbnailerService;
import com.itdominator.api.util.Thumbnailer;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Max;
@ -43,9 +42,7 @@ import lombok.extern.slf4j.Slf4j;
public class ThumbnailerApiController { public class ThumbnailerApiController {
private final ThumbnailerService thumbnailerService; private final ThumbnailerService thumbnailerService;
private final Thumbnailer thumbnailer;
@Value("${videos.filter}")
private final String[] videoFilter;
@PreAuthorize("hasRole('User')") @PreAuthorize("hasRole('User')")
@ -83,60 +80,24 @@ public class ThumbnailerApiController {
@PreAuthorize("hasRole('User')") @PreAuthorize("hasRole('User')")
@GetMapping("/temp-videos-list-test") @GetMapping("/temp-videos-list-test")
public Set<String> getAllVideoFiles() { public Set<String> getAllVideoFiles() throws IOException {
Set<Path> paths = collectVideoFilePaths("/home/abaddon/Downloads"); Set<Path> paths = thumbnailer.collectVideoFilePaths("/home/abaddon/Downloads");
Set<String> files = new HashSet<>(); Set<String> files = new HashSet<>();
generateThumbnails(paths); thumbnailer.generateThumbnails(paths);
for (Path path : paths) { for (Path path : paths) {
files.add( path.getFileName().toString() ); String fileName = path.getFileName().toString();
String fileHash = DigestUtils.sha256Hex(fileName);
// files.add( path.getFileName().toString() );
files.add( path.toString() );
thumbnailerService.saveThumbnail(
new Thumbnails(fileName, fileHash, Files.readAllBytes( Path.of("/tmp/" + fileHash + ".jpg") ) )
);
} }
return files; return files;
} }
public Set<Path> collectVideoFilePaths(final String dir) {
Set<Path> paths = new HashSet<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream( Paths.get(dir) )) {
for (Path path : stream) {
if ( !Files.isDirectory(path) ) {
String target = path.getFileName().toString();
for (String filterItem : videoFilter) {
if ( target.endsWith(filterItem) ) {
paths.add(path);
}
}
}
}
} catch (IOException e) {
log.debug("Invalid path given to scan...");
}
return paths;
}
public void generateThumbnails(Set<Path> paths) {
for (Path path : paths) {
String fileName = path.getFileName().toString();
String fileHash = DigestUtils.sha256Hex(fileName);
generateThumbnail(path.toString(), "/home/abaddon/Downloads/tmp/" + fileHash + ".jpg","65%");
}
}
// proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", scrub_percent, "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_path])
public void generateThumbnail(final String full_path, final String hash_img_path, final String scrub_percent) {
try {
ProcessBuilder pb = new ProcessBuilder("ffmpegthumbnailer", "-t", scrub_percent, "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_path);
Process p = pb.start();
} catch (Exception e) {
log.debug("Thumbnail couldn't be generated...");
// Note: Need supporting logic for failed loads. Maybe return empty byte[]
}
}
} }

View File

@ -5,6 +5,8 @@ import java.io.Serializable;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
@ -24,6 +26,7 @@ public class Thumbnails implements Serializable {
@Id @Id
@Column(name = "id", nullable = false) @Column(name = "id", nullable = false)
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
@GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@Column(name = "file_name", nullable = false) @Column(name = "file_name", nullable = false)
@ -35,4 +38,11 @@ public class Thumbnails implements Serializable {
@Column(name = "image", columnDefinition="BLOB NOT NULL") @Column(name = "image", columnDefinition="BLOB NOT NULL")
private byte[] image; private byte[] image;
public Thumbnails(String fileName, String fileHash, byte[] image) {
this.fileName = fileName;
this.fileHash = fileHash;
this.image = image;
}
} }

View File

@ -24,4 +24,5 @@ public interface ThumbnailRepository extends JpaRepository<Thumbnails, Thumbnail
@Query(value = "SELECT path FROM thumbnails WHERE id = :id", nativeQuery = true) @Query(value = "SELECT path FROM thumbnails WHERE id = :id", nativeQuery = true)
ThumbnailDto findThumbnailById(int id); ThumbnailDto findThumbnailById(int id);
} }

View File

@ -8,12 +8,14 @@ import org.springframework.validation.annotation.Validated;
import com.itdominator.api.dto.ThumbnailDto; import com.itdominator.api.dto.ThumbnailDto;
import com.itdominator.api.dto.ThumbnailSearchCriteria; import com.itdominator.api.dto.ThumbnailSearchCriteria;
import com.itdominator.api.entities.Thumbnails;
import com.itdominator.api.repositories.ThumbnailRepository; import com.itdominator.api.repositories.ThumbnailRepository;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
@Validated @Validated
@ -46,4 +48,8 @@ public class ThumbnailerService {
return thumbnailRepository.getAllThumbnails(); return thumbnailRepository.getAllThumbnails();
} }
public void saveThumbnail(final Thumbnails thumbnail) {
thumbnailRepository.save(thumbnail);
}
} }

View File

@ -0,0 +1,67 @@
package com.itdominator.api.util;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class Thumbnailer {
@Value("${videos.filter}")
private final String[] videoFilter;
public Set<Path> collectVideoFilePaths(final String dir) throws IOException {
Set<Path> paths = new HashSet<>();
DirectoryStream<Path> stream = Files.newDirectoryStream( Paths.get(dir) );
for (Path path : stream) {
if ( !Files.isDirectory(path) ) {
String target = path.getFileName().toString();
for (String filterItem : videoFilter) {
if ( target.endsWith(filterItem) ) {
paths.add(path);
}
}
}
}
return paths;
}
public void generateThumbnails(Set<Path> paths) throws IOException {
for (Path path : paths) {
String fileName = path.getFileName().toString();
String fileHash = DigestUtils.sha256Hex(fileName);
generateThumbnail(path.toString(), "/tmp/" + fileHash + ".jpg","65%");
}
}
// proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", scrub_percent, "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_path])
private void generateThumbnail(final String full_path, final String hash_img_path, final String scrub_percent) throws IOException {
ProcessBuilder pb = new ProcessBuilder("ffmpegthumbnailer", "-t", scrub_percent, "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_path);
Process p = pb.start();
while (p.isAlive()) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}