Initial code commit - POC for .dci file writing/metadata extraction
This commit is contained in:
parent
573fe97f61
commit
8f3da69661
15
.idea/git_toolbox_prj.xml
generated
Normal file
15
.idea/git_toolbox_prj.xml
generated
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GitToolBoxProjectSettings">
|
||||||
|
<option name="commitMessageIssueKeyValidationOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
<option name="commitMessageValidationEnabledOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
100
player.api/assets/seed.cypher
Normal file
100
player.api/assets/seed.cypher
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// === MEMBERS ===
|
||||||
|
CREATE (:Member {name: "Onye"});
|
||||||
|
CREATE (:Member {name: "Eric Westerhold"});
|
||||||
|
CREATE (:Member {name: "Andrew Manzaneres"});
|
||||||
|
|
||||||
|
// === CORPS ===
|
||||||
|
CREATE (:Corps {name: "Bluecoats"});
|
||||||
|
CREATE (:Corps {name: "Blue Devils"});
|
||||||
|
|
||||||
|
// === SHOWS ===
|
||||||
|
CREATE (:Show {title: "To Look For America", year: 2017});
|
||||||
|
CREATE (:Show {title: "Kinetic Noise", year: 2015});
|
||||||
|
CREATE (:Show {title: "Re:Write of Spring", year: 2013});
|
||||||
|
|
||||||
|
// === COMPOSERS ===
|
||||||
|
MERGE (ps:Composer {name: "Paul Simon"})
|
||||||
|
MERGE (rw:Composer {name: "Rufus Wainwright"})
|
||||||
|
MERGE (de:Composer {name: "Duke Ellington"})
|
||||||
|
MERGE (is:Composer {name: "Igor Stravinsky"})
|
||||||
|
MERGE (sb:Composer {name: "Steven Bryant"})
|
||||||
|
MERGE (lc:Composer {name: "Leonard Cohen"})
|
||||||
|
MERGE (sr:Composer {name: "Steve Reich"})
|
||||||
|
MERGE (ja:Composer {name: "John Adams"})
|
||||||
|
MERGE (jan:Composer {name: "John Anderson"})
|
||||||
|
MERGE (bi:Composer {name: "Bon Iver"})
|
||||||
|
MERGE (mg:Composer {name: "Michael Gordon"})
|
||||||
|
MERGE (tb:Composer {name: "The Books"})
|
||||||
|
MERGE (uz:Composer {name: "Univers Zero"})
|
||||||
|
|
||||||
|
// === PIECES ===
|
||||||
|
MERGE (a:Piece {title: "America"})-[:COMPOSED_BY]->(ps)
|
||||||
|
MERGE (ag:Piece {title: "Agnus Dei"})-[:COMPOSED_BY]->(rw)
|
||||||
|
MERGE (sp:Piece {title: "Spring"})-[:COMPOSED_BY]->(de)
|
||||||
|
MERGE (eb:Piece {title: "Ebony Concerto"})-[:COMPOSED_BY]->(is)
|
||||||
|
MERGE (cc:Piece {title: "Concerto"})-[:COMPOSED_BY]->(sb)
|
||||||
|
MERGE (hl:Piece {title: "Hallelujah"})-[:COMPOSED_BY]->(lc)
|
||||||
|
MERGE (cl:Piece {title: "City Life"})-[:COMPOSED_BY]->(sr)
|
||||||
|
MERGE (rs:Piece {title: "The Rite of Spring"})-[:COMPOSED_BY]->(is)
|
||||||
|
MERGE (sl:Piece {title: "Shaker Loops"})-[:COMPOSED_BY]->(ja)
|
||||||
|
MERGE (sl)-[:COMPOSED_BY]->(jan)
|
||||||
|
MERGE (ec:Piece {title: "Electric Counterpoint"})-[:COMPOSED_BY]->(sr)
|
||||||
|
MERGE (wd:Piece {title: "Woods"})-[:COMPOSED_BY]->(bi)
|
||||||
|
MERGE (gt:Piece {title: "Gene Takes A Drink"})-[:COMPOSED_BY]->(mg)
|
||||||
|
MERGE (ad:Piece {title: "An Animated Description Of Mr Maps"})-[:COMPOSED_BY]->(tb)
|
||||||
|
MERGE (ds:Piece {title: "Dense"})-[:COMPOSED_BY]->(uz);
|
||||||
|
|
||||||
|
// === RELATIONSHIPS: Shows → Corps ===
|
||||||
|
MATCH (s1:Show {title: "To Look For America"}), (c1:Corps {name: "Bluecoats"})
|
||||||
|
CREATE (s1)-[:FIELD_BY]->(c1);
|
||||||
|
|
||||||
|
MATCH (s2:Show {title: "Kinetic Noise"}), (c2:Corps {name: "Bluecoats"})
|
||||||
|
CREATE (s2)-[:FIELD_BY]->(c2);
|
||||||
|
|
||||||
|
MATCH (s3:Show {title: "Re:Write of Spring"}), (c3:Corps {name: "Blue Devils"})
|
||||||
|
CREATE (s3)-[:FIELD_BY]->(c3);
|
||||||
|
|
||||||
|
// === RELATIONSHIPS: Members → Shows ===
|
||||||
|
MATCH (m1:Member {name: "Onye"}), (s1:Show {title: "To Look For America"})
|
||||||
|
CREATE (m1)-[:PERFORMED_IN]->(s1);
|
||||||
|
|
||||||
|
MATCH (m2:Member {name: "Eric Westerhold"}), (s2:Show {title: "Kinetic Noise"})
|
||||||
|
CREATE (m2)-[:PERFORMED_IN]->(s2);
|
||||||
|
|
||||||
|
MATCH (m3:Member {name: "Andrew Manzaneres"}), (s3:Show {title: "Re:Write of Spring"})
|
||||||
|
CREATE (m3)-[:PERFORMED_IN]->(s3);
|
||||||
|
|
||||||
|
// === RELATIONSHIPS: Shows → Pieces ===
|
||||||
|
MATCH (s:Show {title: "To Look For America"}),
|
||||||
|
(a:Piece {title: "America"}),
|
||||||
|
(ag:Piece {title: "Agnus Dei"}),
|
||||||
|
(sp:Piece {title: "Spring"}),
|
||||||
|
(eb:Piece {title: "Ebony Concerto"}),
|
||||||
|
(cc:Piece {title: "Concerto"}),
|
||||||
|
(hl:Piece {title: "Hallelujah"}),
|
||||||
|
(cl:Piece {title: "City Life"})
|
||||||
|
CREATE (s)-[:FEATURED]->(a),
|
||||||
|
(s)-[:FEATURED]->(ag),
|
||||||
|
(s)-[:FEATURED]->(sp),
|
||||||
|
(s)-[:FEATURED]->(eb),
|
||||||
|
(s)-[:FEATURED]->(cc),
|
||||||
|
(s)-[:FEATURED]->(hl),
|
||||||
|
(s)-[:FEATURED]->(cl);
|
||||||
|
|
||||||
|
MATCH (s:Show {title: "Re:Write of Spring"}),
|
||||||
|
(rs:Piece {title: "The Rite of Spring"})
|
||||||
|
CREATE (s)-[:FEATURED]->(rs);
|
||||||
|
|
||||||
|
MATCH (s:Show {title: "Kinetic Noise"}),
|
||||||
|
(sl:Piece {title: "Shaker Loops"}),
|
||||||
|
(ec:Piece {title: "Electric Counterpoint"}),
|
||||||
|
(wd:Piece {title: "Woods"}),
|
||||||
|
(gt:Piece {title: "Gene Takes A Drink"}),
|
||||||
|
(ad:Piece {title: "An Animated Description Of Mr Maps"}),
|
||||||
|
(ds:Piece {title: "Dense"})
|
||||||
|
CREATE (s)-[:FEATURED]->(sl),
|
||||||
|
(s)-[:FEATURED]->(ec),
|
||||||
|
(s)-[:FEATURED]->(wd),
|
||||||
|
(s)-[:FEATURED]->(gt),
|
||||||
|
(s)-[:FEATURED]->(ad),
|
||||||
|
(s)-[:FEATURED]->(ds);
|
||||||
29
player.api/src/main/java/Scratch.java
Normal file
29
player.api/src/main/java/Scratch.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import com.dci.aaronic.player.io.DCIFileMetadataContainer;
|
||||||
|
import com.dci.aaronic.player.io.DCIFileWriter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Scratch {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
File test_file = new File("C:\\Users\\kacar\\Desktop\\Data Projects\\DCIPlayer\\player.api\\player.api\\assets\\Bluecoats_2015_Kinetic_Noise.mp4");
|
||||||
|
DCIFileMetadataContainer metadata = null;
|
||||||
|
try {
|
||||||
|
metadata = DCIFileMetadataContainer.extract(test_file.getName());
|
||||||
|
|
||||||
|
System.out.println(metadata);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File testOut = new File("C:\\Users\\kacar\\Desktop\\Data Projects\\DCIPlayer\\player.api\\player.api\\assets\\Bluecoats_2015_Kinetic_Noise.dci");
|
||||||
|
DCIFileWriter writer = new DCIFileWriter();
|
||||||
|
writer.write(test_file, metadata, testOut);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.dci.aaronic.player.api;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package com.dci.aaronic.player.io;
|
||||||
|
|
||||||
|
import com.dci.aaronic.player.models.Corps;
|
||||||
|
import com.dci.aaronic.player.utils.Utils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class DCIFileMetadataContainer {
|
||||||
|
public int year;
|
||||||
|
public String title;
|
||||||
|
public String corps;
|
||||||
|
|
||||||
|
public DCIFileMetadataContainer() {}
|
||||||
|
|
||||||
|
public DCIFileMetadataContainer(int year, String title, String corps) {
|
||||||
|
this.year = year;
|
||||||
|
this.title = title;
|
||||||
|
this.corps = corps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYear(int year) {
|
||||||
|
this.year = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCorps() {
|
||||||
|
return corps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorps(String corps) {
|
||||||
|
this.corps = corps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCIFileMetadataContainer extract(String fileName) throws IOException {
|
||||||
|
Pattern yearPattern = Pattern.compile("\\d{4}");
|
||||||
|
Matcher yearMatcher = yearPattern.matcher(fileName);
|
||||||
|
String year = null;
|
||||||
|
if (yearMatcher.find()) {
|
||||||
|
year = yearMatcher.group();
|
||||||
|
}
|
||||||
|
String foundCorps = null;
|
||||||
|
for (Corps corps: Utils.ALL_CORPS) {
|
||||||
|
if (fileName.contains(corps.getName())) {
|
||||||
|
foundCorps = corps.getName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
|
||||||
|
|
||||||
|
String title = fileName;
|
||||||
|
if (foundCorps != null) {
|
||||||
|
title = title.replace(foundCorps, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year != null) {
|
||||||
|
title = title.replace(year, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileExtension != null) {
|
||||||
|
title = title.replace(fileExtension, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
title = title.replace("_", " ");
|
||||||
|
title = title.trim();
|
||||||
|
return new DCIFileMetadataContainer(Integer.parseInt(year), title, foundCorps);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "DCIFileMetadataContainer{" +
|
||||||
|
"year=" + year +
|
||||||
|
", title='" + title + '\'' +
|
||||||
|
", corps='" + corps + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.dci.aaronic.player.io;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DCIFileMetadataSerializer {
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
public static byte[] serialize(DCIFileMetadataContainer metadata) throws IOException {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsBytes(metadata);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new IOException("Error serializing metadata: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCIFileMetadataContainer deserialize(byte[] bytes) throws IOException {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(bytes, DCIFileMetadataContainer.class);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new IOException("Error deserializing metadata: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package com.dci.aaronic.player.io;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
public class DCIFileReader {
|
||||||
|
|
||||||
|
private static final byte[] MAGIC = ".DCI".getBytes();
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
public void read(File file) throws IOException{
|
||||||
|
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
|
||||||
|
byte[] magic = new byte[MAGIC.length];
|
||||||
|
in.readFully(magic);
|
||||||
|
if (!Arrays.equals(magic, MAGIC)) {
|
||||||
|
throw new IOException("Header mismatch - not a valid .DCI file");
|
||||||
|
}
|
||||||
|
int version = in.readInt();
|
||||||
|
if (version != 1) {
|
||||||
|
throw new IOException("Unsupported version: " + version);
|
||||||
|
}
|
||||||
|
int metaLength = in.readInt();
|
||||||
|
byte[] meta = new byte[metaLength];
|
||||||
|
in.readFully(meta);
|
||||||
|
Map<String, Object> metaMap = objectMapper.readValue(meta, Map.class); // <1>
|
||||||
|
|
||||||
|
System.out.println(metaMap);
|
||||||
|
|
||||||
|
byte[] content = in.readAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package com.dci.aaronic.player.io;
|
||||||
|
|
||||||
|
import jdk.jshell.spi.ExecutionControl;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
//Convert MP4 to DCI
|
||||||
|
|
||||||
|
public class DCIFileWriter {
|
||||||
|
|
||||||
|
private static final byte[] MAGIC = ".DCI".getBytes();
|
||||||
|
|
||||||
|
public void write(File file, DCIFileMetadataContainer metadata, File outputFile) throws IOException {
|
||||||
|
byte[] content = Files.readAllBytes(file.toPath());
|
||||||
|
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile))) {
|
||||||
|
out.write(MAGIC);
|
||||||
|
out.writeInt(1);
|
||||||
|
byte[] meta = DCIFileMetadataSerializer.serialize(metadata);
|
||||||
|
out.writeInt(meta.length);
|
||||||
|
out.write(meta);
|
||||||
|
out.write(content);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
System.out.println("Error creating DCI file: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public class Corps {
|
||||||
|
public String name;
|
||||||
|
public int foundingYear;
|
||||||
|
public String homeCity;
|
||||||
|
public String homeState;
|
||||||
|
public String[] aliases;
|
||||||
|
|
||||||
|
|
||||||
|
public Corps(String name, int foundingYear, String homeCity, String homeState, String[] aliases) {
|
||||||
|
this.name = name;
|
||||||
|
this.foundingYear = foundingYear;
|
||||||
|
this.homeCity = homeCity;
|
||||||
|
this.homeState = homeState;
|
||||||
|
this.aliases = aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public class CorpsProgram {
|
||||||
|
|
||||||
|
private Corps _corps;
|
||||||
|
private MusicSelection[] _reportoires;
|
||||||
|
private int _year;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public class CorpsStaff {
|
||||||
|
|
||||||
|
public Member President;
|
||||||
|
public Member BrassCaptionHead;
|
||||||
|
public Member PercussionCaptionHead;
|
||||||
|
public Member VisualCaptionHead;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public class Member {
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public class MusicSelection {
|
||||||
|
|
||||||
|
public String title;
|
||||||
|
public String subtitle;
|
||||||
|
public String composer;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.dci.aaronic.player.models;
|
||||||
|
|
||||||
|
public enum Section {
|
||||||
|
BRASS,
|
||||||
|
PERCUSSION,
|
||||||
|
COLORGUARD;
|
||||||
|
|
||||||
|
public enum Subsection {
|
||||||
|
TRUMPETS(BRASS),
|
||||||
|
MELLOPHONES(BRASS),
|
||||||
|
BARITONES(BRASS),
|
||||||
|
CONTRAS(BRASS),
|
||||||
|
SNARES(PERCUSSION),
|
||||||
|
TENORS(PERCUSSION),
|
||||||
|
BASSES(PERCUSSION),
|
||||||
|
CYMBALS(PERCUSSION),
|
||||||
|
FRONTENSEMBLE(PERCUSSION),
|
||||||
|
FLAGS(COLORGUARD),
|
||||||
|
RIFLESANDSABRES(COLORGUARD);
|
||||||
|
|
||||||
|
private final Section _section;
|
||||||
|
|
||||||
|
Subsection(Section section) {
|
||||||
|
_section = section;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Section getSection() {
|
||||||
|
return _section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.dci.aaronic.player.utils;
|
||||||
|
|
||||||
|
import com.dci.aaronic.player.models.Corps;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
private Utils() {}
|
||||||
|
|
||||||
|
public static List<Corps> ALL_CORPS = List.of(
|
||||||
|
new Corps("Bluecoats", 1974, "Canton", "Ohio",
|
||||||
|
new String[]{
|
||||||
|
"Bluecoats",
|
||||||
|
"Bloo"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package com.dci.aaronic.player.api;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class ApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user