initial commit
This commit is contained in:
commit
d826999380
40
.classpath
Normal file
40
.classpath
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/bin/
|
||||||
|
/target/
|
||||||
|
/dependency-reduced-pom.xml
|
||||||
|
/library
|
23
.project
Normal file
23
.project
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>VideoBaseV2</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
12
.settings/org.eclipse.jdt.core.prefs
Normal file
12
.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=11
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
|
||||||
|
org.eclipse.jdt.core.compiler.release=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.source=11
|
4
.settings/org.eclipse.m2e.core.prefs
Normal file
4
.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# VideoBase
|
||||||
|
A simple file-based video library
|
||||||
|
|
||||||
|
(not to be confused with the identically named project located [here](https://github.com/MrLetsplay2003/VideoBase))
|
||||||
|
|
||||||
|
## Planned features
|
||||||
|
- [ ] REST API supporting fetching videos and metadata, authentication and editing metadata (no video upload)
|
||||||
|
- [ ] Frontend based on the aforementioned REST API
|
||||||
|
- [ ] API for easy integration into other projects
|
40
pom.xml
Normal file
40
pom.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>me.mrletsplay</groupId>
|
||||||
|
<artifactId>VideoBaseV2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>src/main/java</sourceDirectory>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>11</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>Graphite-Official</id>
|
||||||
|
<url>https://maven.graphite-official.com/releases</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.mrletsplay</groupId>
|
||||||
|
<artifactId>MrCore</artifactId>
|
||||||
|
<version>4.6.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.mrletsplay</groupId>
|
||||||
|
<artifactId>SimpleHTTPServer</artifactId>
|
||||||
|
<version>2.1-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
19
src/main/java/me/mrletsplay/videobase/Config.java
Normal file
19
src/main/java/me/mrletsplay/videobase/Config.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package me.mrletsplay.videobase;
|
||||||
|
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConvertible;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONValue;
|
||||||
|
|
||||||
|
public class Config implements JSONConvertible {
|
||||||
|
|
||||||
|
@JSONValue
|
||||||
|
private String libraryPath;
|
||||||
|
|
||||||
|
private Config() {}
|
||||||
|
|
||||||
|
public static Config createDefault() {
|
||||||
|
Config config = new Config();
|
||||||
|
config.libraryPath = "library";
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
52
src/main/java/me/mrletsplay/videobase/VideoBase.java
Normal file
52
src/main/java/me/mrletsplay/videobase/VideoBase.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package me.mrletsplay.videobase;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import me.mrletsplay.simplehttpserver.http.server.HttpServer;
|
||||||
|
import me.mrletsplay.videobase.library.Library;
|
||||||
|
import me.mrletsplay.videobase.rest.LibraryAPI;
|
||||||
|
import me.mrletsplay.videobase.util.Hash;
|
||||||
|
|
||||||
|
public class VideoBase {
|
||||||
|
|
||||||
|
public static final Logger LOGGER = Logger.getLogger(VideoBase.class.getName());
|
||||||
|
|
||||||
|
private static ScheduledExecutorService executor;
|
||||||
|
private static Library library;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
executor = Executors.newScheduledThreadPool(0);
|
||||||
|
|
||||||
|
// Verify hash is working
|
||||||
|
Hash.hash("test");
|
||||||
|
|
||||||
|
loadLibrary();
|
||||||
|
executor.scheduleWithFixedDelay(VideoBase::loadLibrary, 10, 10, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
HttpServer server = new HttpServer(HttpServer.newConfigurationBuilder()
|
||||||
|
.hostBindAll()
|
||||||
|
.port(6969)
|
||||||
|
.poolSize(20)
|
||||||
|
.ioWorkers(3)
|
||||||
|
.create());
|
||||||
|
|
||||||
|
new LibraryAPI().register(server.getDocumentProvider());
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Library getLibrary() {
|
||||||
|
return library;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void loadLibrary() {
|
||||||
|
library = Library.load(Path.of("/mnt/wd4tb/Files/ytdl/Aliensrock/"));
|
||||||
|
|
||||||
|
System.out.println(library.getVideos());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
149
src/main/java/me/mrletsplay/videobase/library/Library.java
Normal file
149
src/main/java/me/mrletsplay/videobase/library/Library.java
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package me.mrletsplay.videobase.library;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.mrletsplay.mrcore.json.JSONObject;
|
||||||
|
import me.mrletsplay.mrcore.json.JSONParseException;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConverter;
|
||||||
|
import me.mrletsplay.videobase.VideoBase;
|
||||||
|
import me.mrletsplay.videobase.util.Hash;
|
||||||
|
|
||||||
|
public class Library {
|
||||||
|
|
||||||
|
public static final String
|
||||||
|
METADATA_NAME = "meta.json",
|
||||||
|
VIDEO_METADATA_SUFFIX = ".meta.json";
|
||||||
|
|
||||||
|
private Path path;
|
||||||
|
private List<Video> videos;
|
||||||
|
|
||||||
|
public Library(Path path, List<Video> videos) {
|
||||||
|
Objects.requireNonNull(path, "path");
|
||||||
|
Objects.requireNonNull(videos, "videos");
|
||||||
|
|
||||||
|
this.path = path;
|
||||||
|
this.videos = videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Video> getVideos() {
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Video findVideoById(String id) {
|
||||||
|
return videos.stream()
|
||||||
|
.filter(v -> v.getId().equals(id))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the videos for the given series and/or author sorted by their index
|
||||||
|
* @param series The series or {@code null} to not filter by series
|
||||||
|
* @param author The author or {@code null} to not filter by author
|
||||||
|
* @return The videos matching the given criteria
|
||||||
|
*/
|
||||||
|
public List<Video> findVideosBy(String series, String author) { // TODO: Take VideoMetadata to allow any parameter from meta
|
||||||
|
return videos.stream()
|
||||||
|
.filter(v -> (series == null || series.equals(v.getMetadata().getSeries()))
|
||||||
|
&& (author == null || author.equals(v.getMetadata().getAuthor())))
|
||||||
|
.sorted(Comparator.comparing(v -> v.getMetadata().getIndex()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSeries() {
|
||||||
|
return videos.stream()
|
||||||
|
.map(v -> v.getMetadata().getSeries())
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAuthors() {
|
||||||
|
return videos.stream()
|
||||||
|
.map(v -> v.getMetadata().getAuthor())
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Library load(Path path) {
|
||||||
|
List<Video> videos = new ArrayList<>();
|
||||||
|
load(path, path, videos, VideoMetadata.DEFAULT_METADATA);
|
||||||
|
return new Library(path, videos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void load(Path rootPath, Path path, List<Video> videos, VideoMetadata parentDefaultMetadata) {
|
||||||
|
if(!Files.isDirectory(path)) return;
|
||||||
|
|
||||||
|
LibraryMetadata libraryMeta = null;
|
||||||
|
VideoMetadata defaultMetadata = parentDefaultMetadata;
|
||||||
|
|
||||||
|
Path metaPath = path.resolve("meta.json");
|
||||||
|
if(Files.isRegularFile(metaPath)) {
|
||||||
|
try {
|
||||||
|
JSONObject obj = new JSONObject(Files.readString(metaPath));
|
||||||
|
libraryMeta = JSONConverter.decodeObject(obj, LibraryMetadata.class);
|
||||||
|
defaultMetadata = VideoMetadata.inherit(defaultMetadata, libraryMeta.getDefault());
|
||||||
|
}catch(IOException | JSONParseException | ClassCastException e) {
|
||||||
|
VideoBase.LOGGER.log(Level.WARNING, "Failed to parse metadata at " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for(Path subPath : Files.walk(path, 1)
|
||||||
|
.filter(p -> path.equals(p.getParent()))
|
||||||
|
.sorted(Comparator.comparing(p -> p.getFileName().toString()))
|
||||||
|
.collect(Collectors.toList())) {
|
||||||
|
String fileName = subPath.getFileName().toString();
|
||||||
|
String fileNameNoExt = fileName;
|
||||||
|
if(fileNameNoExt.contains(".")) {
|
||||||
|
fileNameNoExt = fileNameNoExt.substring(0, fileNameNoExt.lastIndexOf('.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Files.isDirectory(subPath)) {
|
||||||
|
load(rootPath, subPath, videos, defaultMetadata);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileName.equals(METADATA_NAME) || fileName.endsWith(VIDEO_METADATA_SUFFIX)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoMetadata inferredMetadata = new VideoMetadata(new JSONObject(Map.of(
|
||||||
|
VideoMetadata.FIELD_TITLE, fileNameNoExt,
|
||||||
|
VideoMetadata.FIELD_SERIES, path.getFileName().toString()
|
||||||
|
)));
|
||||||
|
|
||||||
|
VideoMetadata videoMeta = VideoMetadata.inherit(defaultMetadata, inferredMetadata);
|
||||||
|
|
||||||
|
Path videoMetaPath = path.resolve(subPath.getFileName().toString() + VIDEO_METADATA_SUFFIX);
|
||||||
|
if(Files.isRegularFile(videoMetaPath)) {
|
||||||
|
try {
|
||||||
|
JSONObject obj = new JSONObject(Files.readString(videoMetaPath));
|
||||||
|
videoMeta = VideoMetadata.inherit(videoMeta, JSONConverter.decodeObject(obj, VideoMetadata.class));
|
||||||
|
}catch(IOException | JSONParseException | ClassCastException e) {
|
||||||
|
VideoBase.LOGGER.log(Level.WARNING, "Failed to parse metadata at " + path, e);
|
||||||
|
}
|
||||||
|
}else if(libraryMeta != null && libraryMeta.getOverrides().containsKey(fileName)) {
|
||||||
|
videoMeta = VideoMetadata.inherit(videoMeta, libraryMeta.getOverrides().get(fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = Hash.hash(rootPath.relativize(subPath).toString());
|
||||||
|
videos.add(new Video(subPath, id, videoMeta == null ? VideoMetadata.DEFAULT_METADATA : videoMeta));
|
||||||
|
}
|
||||||
|
}catch(IOException e) {
|
||||||
|
VideoBase.LOGGER.log(Level.WARNING, "Failed to load folder at " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package me.mrletsplay.videobase.library;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import me.mrletsplay.mrcore.json.JSONObject;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConstructor;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConverter;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConvertible;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONValue;
|
||||||
|
|
||||||
|
public class LibraryMetadata implements JSONConvertible {
|
||||||
|
|
||||||
|
@JSONValue("default")
|
||||||
|
private VideoMetadata defaultMetadata;
|
||||||
|
|
||||||
|
private Map<String, VideoMetadata> overrides;
|
||||||
|
|
||||||
|
@JSONConstructor
|
||||||
|
public LibraryMetadata() {
|
||||||
|
this.overrides = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoMetadata getDefault() {
|
||||||
|
return defaultMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, VideoMetadata> getOverrides() {
|
||||||
|
return overrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDeserialize(JSONObject object) {
|
||||||
|
JSONObject ov = object.optJSONObject("overrides").orElse(null);
|
||||||
|
if(ov != null) {
|
||||||
|
for(String key : ov.keys()) {
|
||||||
|
overrides.put(key, JSONConverter.decodeObject(ov.getJSONObject(key), VideoMetadata.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preSerialize(JSONObject object) {
|
||||||
|
JSONObject ov = new JSONObject();
|
||||||
|
for(String key : overrides.keySet()) {
|
||||||
|
ov.put(key, overrides.get(key).toJSON());
|
||||||
|
}
|
||||||
|
object.put("overrides", ov);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
src/main/java/me/mrletsplay/videobase/library/Video.java
Normal file
34
src/main/java/me/mrletsplay/videobase/library/Video.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package me.mrletsplay.videobase.library;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class Video {
|
||||||
|
|
||||||
|
private Path path;
|
||||||
|
private String id;
|
||||||
|
private VideoMetadata metadata;
|
||||||
|
|
||||||
|
public Video(Path path, String id, VideoMetadata metadata) {
|
||||||
|
this.path = path;
|
||||||
|
this.id = id;
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoMetadata getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{Video: " + id + ", " + path + ", " + metadata + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package me.mrletsplay.videobase.library;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import me.mrletsplay.mrcore.json.JSONObject;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConstructor;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.JSONConvertible;
|
||||||
|
|
||||||
|
public class VideoMetadata implements JSONConvertible {
|
||||||
|
|
||||||
|
public static final String
|
||||||
|
FIELD_SERIES = "series",
|
||||||
|
FIELD_TITLE = "title",
|
||||||
|
FIELD_AUTHOR = "author",
|
||||||
|
FIELD_INDEX = "index";
|
||||||
|
|
||||||
|
public static final String
|
||||||
|
DEFAULT_SERIES = "Unnamed Series",
|
||||||
|
DEFAULT_TITLE = "Unnamed Video",
|
||||||
|
DEFAULT_AUTHOR = "Unnamed Author";
|
||||||
|
|
||||||
|
public static final int
|
||||||
|
DEFAULT_INDEX = 0;
|
||||||
|
|
||||||
|
public static final VideoMetadata DEFAULT_METADATA = new VideoMetadata(new JSONObject(Map.of(
|
||||||
|
FIELD_SERIES, DEFAULT_SERIES,
|
||||||
|
FIELD_TITLE, DEFAULT_TITLE,
|
||||||
|
FIELD_AUTHOR, DEFAULT_AUTHOR,
|
||||||
|
FIELD_INDEX, DEFAULT_INDEX
|
||||||
|
)));
|
||||||
|
|
||||||
|
private JSONObject metadata;
|
||||||
|
|
||||||
|
@JSONConstructor
|
||||||
|
private VideoMetadata() {}
|
||||||
|
|
||||||
|
public VideoMetadata(JSONObject metadata) {
|
||||||
|
Objects.requireNonNull(metadata, "metadata");
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSeries() {
|
||||||
|
return metadata.optString(FIELD_SERIES).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return metadata.optString(FIELD_TITLE).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return metadata.optString(FIELD_AUTHOR).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIndex() {
|
||||||
|
return metadata.optInt(FIELD_INDEX).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDeserialize(JSONObject object) {
|
||||||
|
this.metadata = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preSerialize(JSONObject object) {
|
||||||
|
for(String key : metadata.keys()) {
|
||||||
|
object.set(key, metadata.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return metadata.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VideoMetadata inherit(VideoMetadata parent, VideoMetadata child) {
|
||||||
|
if(parent == null) return child;
|
||||||
|
if(child == null) return parent;
|
||||||
|
|
||||||
|
JSONObject meta = new JSONObject(parent == null ? null : parent.metadata);
|
||||||
|
for(String key : child.metadata.keys()) {
|
||||||
|
meta.set(key, child.metadata.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VideoMetadata(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
104
src/main/java/me/mrletsplay/videobase/rest/LibraryAPI.java
Normal file
104
src/main/java/me/mrletsplay/videobase/rest/LibraryAPI.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package me.mrletsplay.videobase.rest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.mrletsplay.mrcore.json.JSONArray;
|
||||||
|
import me.mrletsplay.mrcore.json.JSONObject;
|
||||||
|
import me.mrletsplay.mrcore.json.converter.SerializationOption;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.HttpRequestMethod;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.HttpStatusCodes;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.endpoint.Endpoint;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.endpoint.EndpointCollection;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.endpoint.RequestParameter;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.request.HttpRequestContext;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.response.JsonResponse;
|
||||||
|
import me.mrletsplay.simplehttpserver.http.response.TextResponse;
|
||||||
|
import me.mrletsplay.videobase.VideoBase;
|
||||||
|
import me.mrletsplay.videobase.library.Library;
|
||||||
|
import me.mrletsplay.videobase.library.Video;
|
||||||
|
|
||||||
|
public class LibraryAPI implements EndpointCollection {
|
||||||
|
|
||||||
|
@Endpoint(method = HttpRequestMethod.GET, path = "")
|
||||||
|
public void getLibrary(HttpRequestContext ctx) {
|
||||||
|
String groupBy = ctx.getRequestedPath().getQuery().getFirst("groupBy", "none").toLowerCase();
|
||||||
|
|
||||||
|
Library library = VideoBase.getLibrary();
|
||||||
|
|
||||||
|
JSONObject libraryObj = new JSONObject();
|
||||||
|
|
||||||
|
JSONObject videosObj = new JSONObject();
|
||||||
|
|
||||||
|
List<String> groups;
|
||||||
|
switch(groupBy) {
|
||||||
|
case "series": {
|
||||||
|
groups = library.getSeries();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "author": {
|
||||||
|
groups = library.getAuthors();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "none":
|
||||||
|
default:
|
||||||
|
groups = List.of("all");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String group : groups) {
|
||||||
|
List<Video> videos;
|
||||||
|
switch(groupBy) {
|
||||||
|
case "series": {
|
||||||
|
videos = library.findVideosBy(group, null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "author": {
|
||||||
|
videos = library.findVideosBy(null, group);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "none":
|
||||||
|
default:
|
||||||
|
videos = library.getVideos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray videosArr = new JSONArray();
|
||||||
|
for(Video video : videos) {
|
||||||
|
videosArr.add(videoToJSON(video));
|
||||||
|
}
|
||||||
|
videosObj.put(group, videosArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!"none".equals("groupBy")) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
libraryObj.put("videos", videosObj);
|
||||||
|
|
||||||
|
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(libraryObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Endpoint(method = HttpRequestMethod.GET, path = "/video/{video}", pathPattern = true)
|
||||||
|
public void getVideo(HttpRequestContext ctx, @RequestParameter("video") String videoId) {
|
||||||
|
Video video = VideoBase.getLibrary().findVideoById(videoId);
|
||||||
|
if(video == null) {
|
||||||
|
ctx.respond(HttpStatusCodes.NOT_FOUND_404, new TextResponse("Not found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(videoToJSON(video)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject videoToJSON(Video video) {
|
||||||
|
JSONObject v = new JSONObject();
|
||||||
|
v.put("id", video.getId());
|
||||||
|
v.put("metadata", video.getMetadata().toJSON(SerializationOption.DONT_INCLUDE_CLASS));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBasePath() {
|
||||||
|
return "/api/library";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/main/java/me/mrletsplay/videobase/util/Hash.java
Normal file
24
src/main/java/me/mrletsplay/videobase/util/Hash.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package me.mrletsplay.videobase.util;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class Hash {
|
||||||
|
|
||||||
|
private static final MessageDigest SHA_3;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
SHA_3 = MessageDigest.getInstance("SHA-256");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("Failed to initialize hash", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String hash(String input) {
|
||||||
|
return new BigInteger(1, SHA_3.digest(input.getBytes(StandardCharsets.UTF_8))).toString(36);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user