Compare commits
2 commits
ff56f5de69
...
481f97b378
Author | SHA1 | Date | |
---|---|---|---|
DataHoarder | 481f97b378 | ||
DataHoarder | 6f710cde4b |
250
dbschema/default.esdl
Normal file
250
dbschema/default.esdl
Normal file
|
@ -0,0 +1,250 @@
|
|||
module default {
|
||||
|
||||
}
|
||||
|
||||
module metadata {
|
||||
scalar type ReleaseMediaSource extending enum<CD, Web, Analog>;
|
||||
|
||||
type License {
|
||||
property name -> str;
|
||||
property url -> str {
|
||||
constraint exclusive;
|
||||
}
|
||||
}
|
||||
|
||||
type Name {
|
||||
required property language -> str;
|
||||
required property value -> str;
|
||||
}
|
||||
|
||||
type Tag {
|
||||
required property name -> str {
|
||||
constraint exclusive;
|
||||
}
|
||||
|
||||
index on (.name);
|
||||
|
||||
multi link albums := .<tags[is metadata::Album];
|
||||
|
||||
multi link songs := .<tags[is metadata::Song];
|
||||
}
|
||||
|
||||
type Album {
|
||||
required multi link names -> Name;
|
||||
link cover -> media::Art;
|
||||
multi link art -> media::Art;
|
||||
multi link artists -> Artist {
|
||||
property kind -> str;
|
||||
}
|
||||
multi link tags -> Tag;
|
||||
|
||||
multi link releases -> Release {
|
||||
constraint exclusive;
|
||||
}
|
||||
|
||||
property metadata -> json;
|
||||
}
|
||||
|
||||
type Release {
|
||||
property media_source -> ReleaseMediaSource;
|
||||
property release_date -> datetime;
|
||||
multi link discs -> Disc {
|
||||
property number -> int32;
|
||||
constraint exclusive;
|
||||
}
|
||||
|
||||
link album := .<releases[is Album];
|
||||
|
||||
link license -> License;
|
||||
property metadata -> json;
|
||||
}
|
||||
|
||||
type Disc {
|
||||
property catalog_number -> str;
|
||||
multi link tracks -> Song {
|
||||
property number -> int32;
|
||||
}
|
||||
property metadata -> json;
|
||||
|
||||
link release := .<discs[is Release];
|
||||
|
||||
index on (.catalog_number);
|
||||
}
|
||||
|
||||
type Artist {
|
||||
required multi link names -> Name;
|
||||
property metadata -> json;
|
||||
}
|
||||
|
||||
type Song {
|
||||
required multi link names -> Name;
|
||||
multi link artists -> Artist {
|
||||
property kind -> str;
|
||||
}
|
||||
required multi link recordings -> media::Recording {
|
||||
property start_sample -> int64;
|
||||
property end_sample -> int64;
|
||||
}
|
||||
|
||||
multi link tags -> Tag;
|
||||
required property length -> duration;
|
||||
multi link lyrics -> media::Lyrics;
|
||||
|
||||
property isrc -> str {
|
||||
constraint exclusive;
|
||||
}
|
||||
|
||||
property metadata -> json;
|
||||
|
||||
multi link related -> Song {
|
||||
property kind -> str;
|
||||
}
|
||||
|
||||
multi link discs := .<tracks[is Disc];
|
||||
index on (.isrc);
|
||||
}
|
||||
}
|
||||
|
||||
module media {
|
||||
scalar type LyricsKind extending enum<ASS, LRC, WebVTT, SubRip, Text>;
|
||||
scalar type ArtResourceType extending enum<Original, Large, Small>;
|
||||
|
||||
abstract type Resource {
|
||||
required property hash -> bytes {
|
||||
annotation description := "SHA256 of the resource";
|
||||
}
|
||||
required property size -> int64;
|
||||
required property mime -> str;
|
||||
property metadata -> json;
|
||||
|
||||
multi property sources -> str;
|
||||
property path -> str {
|
||||
constraint exclusive;
|
||||
annotation description := "full path or URI to resource";
|
||||
}
|
||||
property blob -> bytes {
|
||||
annotation description := "full contents of resource";
|
||||
}
|
||||
property name -> str {
|
||||
annotation description := "base name of path / filename";
|
||||
}
|
||||
|
||||
index on (.hash);
|
||||
}
|
||||
|
||||
type Blob extending Resource {
|
||||
|
||||
}
|
||||
|
||||
type Lyrics extending Resource {
|
||||
required property kind -> LyricsKind;
|
||||
required property language -> str;
|
||||
}
|
||||
|
||||
type Art extending Resource {
|
||||
required property kind -> str;
|
||||
required property type -> ArtResourceType;
|
||||
multi link thumbnails -> Art;
|
||||
}
|
||||
|
||||
type RecordingGroup {
|
||||
annotation description := "a group of Recording placed within the same folder/group";
|
||||
property toc -> array<int32>;
|
||||
property crc32 -> int32;
|
||||
property cuetools_crc32 -> int32;
|
||||
property cddb1 -> int32;
|
||||
property discid -> str;
|
||||
property tocid -> str;
|
||||
required multi link recordings -> Recording {
|
||||
property number -> int32;
|
||||
}
|
||||
multi link resources -> Resource {
|
||||
annotation description := "other resources included around the group (same folder, one folder down, and one folder up if applicable)";
|
||||
}
|
||||
}
|
||||
|
||||
type Recording extending Resource {
|
||||
required property processed -> bool {
|
||||
default := false
|
||||
}
|
||||
property crc32 -> int32;
|
||||
property cuetools_crc32 -> int32;
|
||||
property accurip_v1 -> int32;
|
||||
property accurip_v2 -> int32;
|
||||
|
||||
required property length -> duration;
|
||||
required property lossless -> bool;
|
||||
required property sample_rate -> int32;
|
||||
required property channels -> int32;
|
||||
required property samples -> int64;
|
||||
|
||||
link recording_group := .<recordings[is RecordingGroup];
|
||||
link song := .<recordings[is metadata::Song];
|
||||
}
|
||||
}
|
||||
|
||||
module radio {
|
||||
type HistoryEntry {
|
||||
required link song -> metadata::Song;
|
||||
link recording -> media::Recording;
|
||||
required property date -> datetime;
|
||||
property source -> user::User;
|
||||
}
|
||||
}
|
||||
|
||||
module user {
|
||||
|
||||
scalar type KeyKind extending enum<Ed25519, Secp256k1, Secp256r1, Passphrase>;
|
||||
|
||||
type UserGroup {
|
||||
required property name -> str {
|
||||
constraint exclusive;
|
||||
}
|
||||
multi property permissions -> str;
|
||||
}
|
||||
|
||||
type UserKey {
|
||||
required property kind -> KeyKind;
|
||||
required property value -> bytes;
|
||||
}
|
||||
|
||||
type User {
|
||||
required property name -> str {
|
||||
constraint exclusive;
|
||||
}
|
||||
required multi link keys -> UserKey {
|
||||
property name -> str;
|
||||
}
|
||||
required multi link groups -> UserGroup;
|
||||
property metadata -> json;
|
||||
multi link favorites := .<owner[is Favorite];
|
||||
multi link tagged := .<owner[is Tagging];
|
||||
multi link playlists := .<owner[is Playlist];
|
||||
index on (.name);
|
||||
}
|
||||
|
||||
type Favorite {
|
||||
required link owner -> User;
|
||||
required link song -> metadata::Song;
|
||||
multi link tags -> metadata::Tag;
|
||||
index on (.owner);
|
||||
}
|
||||
|
||||
type Tagging {
|
||||
required link owner -> User;
|
||||
required link song -> metadata::Song;
|
||||
multi link tags -> metadata::Tag;
|
||||
index on (.owner);
|
||||
}
|
||||
|
||||
type Playlist {
|
||||
required link owner -> User;
|
||||
multi link songs -> metadata::Song {
|
||||
property number -> int32;
|
||||
}
|
||||
property name -> str;
|
||||
index on (.owner);
|
||||
}
|
||||
|
||||
|
||||
}
|
238
dbschema/migrations/00001.edgeql
Normal file
238
dbschema/migrations/00001.edgeql
Normal file
|
@ -0,0 +1,238 @@
|
|||
CREATE MIGRATION m1cfqatfhjy63l6shobgylrpgg7yhilkvjcuy5kucknb7odov7d6oq
|
||||
ONTO initial
|
||||
{
|
||||
CREATE MODULE media IF NOT EXISTS;
|
||||
CREATE MODULE metadata IF NOT EXISTS;
|
||||
CREATE MODULE radio IF NOT EXISTS;
|
||||
CREATE MODULE user IF NOT EXISTS;
|
||||
CREATE ABSTRACT TYPE media::Resource {
|
||||
CREATE PROPERTY blob -> std::bytes {
|
||||
CREATE ANNOTATION std::description := 'full contents of resource';
|
||||
};
|
||||
CREATE REQUIRED PROPERTY hash -> std::bytes {
|
||||
CREATE ANNOTATION std::description := 'SHA256 of the resource';
|
||||
};
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
CREATE REQUIRED PROPERTY mime -> std::str;
|
||||
CREATE PROPERTY name -> std::str {
|
||||
CREATE ANNOTATION std::description := 'base name of path / filename';
|
||||
};
|
||||
CREATE PROPERTY path -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
CREATE ANNOTATION std::description := 'full path or URI to resource';
|
||||
};
|
||||
CREATE REQUIRED PROPERTY size -> std::int64;
|
||||
CREATE MULTI PROPERTY sources -> std::str;
|
||||
CREATE INDEX ON (.hash);
|
||||
};
|
||||
CREATE TYPE media::RecordingGroup {
|
||||
CREATE PROPERTY toc -> array<std::int32>;
|
||||
CREATE ANNOTATION std::description := 'a group of Recording placed within the same folder/group';
|
||||
CREATE MULTI LINK resources -> media::Resource {
|
||||
CREATE ANNOTATION std::description := 'other resources included around the group (same folder, one folder down, and one folder up if applicable)';
|
||||
};
|
||||
CREATE PROPERTY cddb1 -> std::int32;
|
||||
CREATE PROPERTY crc32 -> std::int32;
|
||||
CREATE PROPERTY cuetools_crc32 -> std::int32;
|
||||
CREATE PROPERTY discid -> std::str;
|
||||
CREATE PROPERTY tocid -> std::str;
|
||||
};
|
||||
CREATE SCALAR TYPE media::ArtResourceType EXTENDING enum<Original, Large, Small>;
|
||||
CREATE TYPE media::Art EXTENDING media::Resource {
|
||||
CREATE MULTI LINK thumbnails -> media::Art;
|
||||
CREATE REQUIRED PROPERTY kind -> std::str;
|
||||
CREATE REQUIRED PROPERTY type -> media::ArtResourceType;
|
||||
};
|
||||
CREATE TYPE metadata::Name {
|
||||
CREATE REQUIRED PROPERTY language -> std::str;
|
||||
CREATE REQUIRED PROPERTY value -> std::str;
|
||||
};
|
||||
CREATE TYPE metadata::Artist {
|
||||
CREATE REQUIRED MULTI LINK names -> metadata::Name;
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
};
|
||||
CREATE TYPE metadata::Album {
|
||||
CREATE MULTI LINK art -> media::Art;
|
||||
CREATE LINK cover -> media::Art;
|
||||
CREATE MULTI LINK artists -> metadata::Artist {
|
||||
CREATE PROPERTY kind -> std::str;
|
||||
};
|
||||
CREATE REQUIRED MULTI LINK names -> metadata::Name;
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
};
|
||||
CREATE TYPE media::Blob EXTENDING media::Resource;
|
||||
CREATE SCALAR TYPE media::LyricsKind EXTENDING enum<ASS, LRC, WebVTT, SubRip, Text>;
|
||||
CREATE TYPE media::Lyrics EXTENDING media::Resource {
|
||||
CREATE REQUIRED PROPERTY kind -> media::LyricsKind;
|
||||
CREATE REQUIRED PROPERTY language -> std::str;
|
||||
};
|
||||
CREATE TYPE metadata::Song {
|
||||
CREATE MULTI LINK lyrics -> media::Lyrics;
|
||||
CREATE MULTI LINK artists -> metadata::Artist {
|
||||
CREATE PROPERTY kind -> std::str;
|
||||
};
|
||||
CREATE REQUIRED MULTI LINK names -> metadata::Name;
|
||||
CREATE PROPERTY isrc -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
CREATE INDEX ON (.isrc);
|
||||
CREATE MULTI LINK related -> metadata::Song {
|
||||
CREATE PROPERTY kind -> std::str;
|
||||
};
|
||||
CREATE REQUIRED PROPERTY length -> std::duration;
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
};
|
||||
CREATE TYPE media::Recording EXTENDING media::Resource {
|
||||
CREATE PROPERTY accurip_v1 -> std::int32;
|
||||
CREATE PROPERTY accurip_v2 -> std::int32;
|
||||
CREATE REQUIRED PROPERTY channels -> std::int32;
|
||||
CREATE PROPERTY crc32 -> std::int32;
|
||||
CREATE PROPERTY cuetools_crc32 -> std::int32;
|
||||
CREATE REQUIRED PROPERTY length -> std::duration;
|
||||
CREATE REQUIRED PROPERTY lossless -> std::bool;
|
||||
CREATE REQUIRED PROPERTY processed -> std::bool {
|
||||
SET default := false;
|
||||
};
|
||||
CREATE REQUIRED PROPERTY sample_rate -> std::int32;
|
||||
CREATE REQUIRED PROPERTY samples -> std::int64;
|
||||
};
|
||||
ALTER TYPE media::RecordingGroup {
|
||||
CREATE REQUIRED MULTI LINK recordings -> media::Recording {
|
||||
CREATE PROPERTY number -> std::int32;
|
||||
};
|
||||
};
|
||||
ALTER TYPE media::Recording {
|
||||
CREATE LINK recording_group := (.<recordings[IS media::RecordingGroup]);
|
||||
};
|
||||
ALTER TYPE metadata::Song {
|
||||
CREATE REQUIRED MULTI LINK recordings -> media::Recording {
|
||||
CREATE PROPERTY end_sample -> std::int64;
|
||||
CREATE PROPERTY start_sample -> std::int64;
|
||||
};
|
||||
};
|
||||
ALTER TYPE media::Recording {
|
||||
CREATE LINK song := (.<recordings[IS metadata::Song]);
|
||||
};
|
||||
CREATE TYPE radio::HistoryEntry {
|
||||
CREATE LINK recording -> media::Recording;
|
||||
CREATE REQUIRED LINK song -> metadata::Song;
|
||||
CREATE REQUIRED PROPERTY date -> std::datetime;
|
||||
};
|
||||
CREATE TYPE metadata::License {
|
||||
CREATE PROPERTY name -> std::str;
|
||||
CREATE PROPERTY url -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
};
|
||||
CREATE SCALAR TYPE metadata::ReleaseMediaSource EXTENDING enum<CD, Web, Analog>;
|
||||
CREATE TYPE metadata::Release {
|
||||
CREATE LINK license -> metadata::License;
|
||||
CREATE PROPERTY media_source -> metadata::ReleaseMediaSource;
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
CREATE PROPERTY release_date -> std::datetime;
|
||||
};
|
||||
ALTER TYPE metadata::Album {
|
||||
CREATE MULTI LINK releases -> metadata::Release {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
};
|
||||
ALTER TYPE metadata::Release {
|
||||
CREATE LINK album := (.<releases[IS metadata::Album]);
|
||||
};
|
||||
CREATE TYPE metadata::Tag {
|
||||
CREATE REQUIRED PROPERTY name -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
CREATE INDEX ON (.name);
|
||||
};
|
||||
ALTER TYPE metadata::Album {
|
||||
CREATE MULTI LINK tags -> metadata::Tag;
|
||||
};
|
||||
ALTER TYPE metadata::Tag {
|
||||
CREATE MULTI LINK albums := (.<tags[IS metadata::Album]);
|
||||
};
|
||||
CREATE TYPE metadata::Disc {
|
||||
CREATE PROPERTY catalog_number -> std::str;
|
||||
CREATE INDEX ON (.catalog_number);
|
||||
CREATE MULTI LINK tracks -> metadata::Song {
|
||||
CREATE PROPERTY number -> std::int32;
|
||||
};
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
};
|
||||
ALTER TYPE metadata::Release {
|
||||
CREATE MULTI LINK discs -> metadata::Disc {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
CREATE PROPERTY number -> std::int32;
|
||||
};
|
||||
};
|
||||
ALTER TYPE metadata::Disc {
|
||||
CREATE LINK release := (.<discs[IS metadata::Release]);
|
||||
};
|
||||
ALTER TYPE metadata::Song {
|
||||
CREATE MULTI LINK discs := (.<tracks[IS metadata::Disc]);
|
||||
CREATE MULTI LINK tags -> metadata::Tag;
|
||||
};
|
||||
ALTER TYPE metadata::Tag {
|
||||
CREATE MULTI LINK songs := (.<tags[IS metadata::Song]);
|
||||
};
|
||||
CREATE TYPE user::Favorite {
|
||||
CREATE REQUIRED LINK song -> metadata::Song;
|
||||
CREATE MULTI LINK tags -> metadata::Tag;
|
||||
};
|
||||
CREATE TYPE user::Tagging {
|
||||
CREATE REQUIRED LINK song -> metadata::Song;
|
||||
CREATE MULTI LINK tags -> metadata::Tag;
|
||||
};
|
||||
CREATE TYPE user::Playlist {
|
||||
CREATE MULTI LINK songs -> metadata::Song {
|
||||
CREATE PROPERTY number -> std::int32;
|
||||
};
|
||||
CREATE PROPERTY name -> std::str;
|
||||
};
|
||||
CREATE TYPE user::UserGroup {
|
||||
CREATE REQUIRED PROPERTY name -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
CREATE MULTI PROPERTY permissions -> std::str;
|
||||
};
|
||||
CREATE SCALAR TYPE user::KeyKind EXTENDING enum<Ed25519, Secp256k1, Secp256r1, Passphrase>;
|
||||
CREATE TYPE user::UserKey {
|
||||
CREATE REQUIRED PROPERTY kind -> user::KeyKind;
|
||||
CREATE REQUIRED PROPERTY value -> std::bytes;
|
||||
};
|
||||
CREATE TYPE user::User {
|
||||
CREATE REQUIRED PROPERTY name -> std::str {
|
||||
CREATE CONSTRAINT std::exclusive;
|
||||
};
|
||||
CREATE INDEX ON (.name);
|
||||
CREATE REQUIRED MULTI LINK groups -> user::UserGroup;
|
||||
CREATE REQUIRED MULTI LINK keys -> user::UserKey {
|
||||
CREATE PROPERTY name -> std::str;
|
||||
};
|
||||
CREATE PROPERTY metadata -> std::json;
|
||||
};
|
||||
ALTER TYPE radio::HistoryEntry {
|
||||
CREATE PROPERTY source -> user::User;
|
||||
};
|
||||
ALTER TYPE user::Favorite {
|
||||
CREATE REQUIRED LINK owner -> user::User;
|
||||
CREATE INDEX ON (.owner);
|
||||
};
|
||||
ALTER TYPE user::User {
|
||||
CREATE MULTI LINK favorites := (.<owner[IS user::Favorite]);
|
||||
};
|
||||
ALTER TYPE user::Playlist {
|
||||
CREATE REQUIRED LINK owner -> user::User;
|
||||
CREATE INDEX ON (.owner);
|
||||
};
|
||||
ALTER TYPE user::User {
|
||||
CREATE MULTI LINK playlists := (.<owner[IS user::Playlist]);
|
||||
};
|
||||
ALTER TYPE user::Tagging {
|
||||
CREATE REQUIRED LINK owner -> user::User;
|
||||
CREATE INDEX ON (.owner);
|
||||
};
|
||||
ALTER TYPE user::User {
|
||||
CREATE MULTI LINK tagged := (.<owner[IS user::Tagging]);
|
||||
};
|
||||
};
|
2
edgedb.toml
Normal file
2
edgedb.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[edgedb]
|
||||
server-version = "1.0"
|
|
@ -12,12 +12,14 @@ import (
|
|||
"git.gammaspectra.live/S.O.N.G/Hibiki/utilities/specializedstore"
|
||||
"git.gammaspectra.live/S.O.N.G/METANOIA/utilities"
|
||||
"github.com/dhowden/tag"
|
||||
"github.com/oriser/regroup"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -268,11 +270,14 @@ func processAudioFiles(files []string) (result fileEntryList) {
|
|||
}
|
||||
|
||||
type DiscHandlerResult struct {
|
||||
TOC TOC
|
||||
CRC32 uint32
|
||||
CueToolsCRC32 uint32
|
||||
Directory string
|
||||
Tracks []DiscHandlerTrack
|
||||
TOC TOC
|
||||
CRC32 uint32
|
||||
CueToolsCRC32 uint32
|
||||
Directory string
|
||||
Tracks []DiscHandlerTrack
|
||||
CommonMetadata map[string]string
|
||||
Identifiers []Name
|
||||
Album string
|
||||
}
|
||||
|
||||
type DiscHandlerTrack struct {
|
||||
|
@ -288,13 +293,12 @@ type DiscHandlerTrack struct {
|
|||
}
|
||||
FileMetadata struct {
|
||||
DiscNumber int
|
||||
Artists []Name
|
||||
Album string
|
||||
AlbumArtist string
|
||||
Artist string
|
||||
Composer string
|
||||
Year int
|
||||
TrackNumber int
|
||||
Title string
|
||||
OriginalTitle string
|
||||
EmbeddedPicture []byte
|
||||
}
|
||||
AudioMetadata struct {
|
||||
|
@ -344,8 +348,9 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan
|
|||
sortedAudioEntries := processAudioFiles(audioFiles)
|
||||
|
||||
disc := &DiscHandlerResult{
|
||||
Directory: pathEntry,
|
||||
TOC: TOC{TocPregap},
|
||||
Directory: pathEntry,
|
||||
TOC: TOC{TocPregap},
|
||||
CommonMetadata: make(map[string]string),
|
||||
}
|
||||
|
||||
result, fullCRC32, fullCTDBCRC32 := sortedAudioEntries.analyze(pathEntry, panakoInstance)
|
||||
|
@ -390,9 +395,98 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan
|
|||
track.FileMetadata.DiscNumber, _ = entry.fileMetadata.Disc()
|
||||
track.FileMetadata.TrackNumber, _ = entry.fileMetadata.Track()
|
||||
track.FileMetadata.Year = entry.fileMetadata.Year()
|
||||
track.FileMetadata.AlbumArtist = entry.fileMetadata.AlbumArtist()
|
||||
track.FileMetadata.Artist = entry.fileMetadata.Artist()
|
||||
track.FileMetadata.Composer = entry.fileMetadata.Composer()
|
||||
if entry.fileMetadata.Artist() != "" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "artist",
|
||||
Name: entry.fileMetadata.Artist(),
|
||||
})
|
||||
}
|
||||
if entry.fileMetadata.AlbumArtist() != "" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "albumartist",
|
||||
Name: entry.fileMetadata.AlbumArtist(),
|
||||
})
|
||||
}
|
||||
if entry.fileMetadata.Composer() != "" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "composer",
|
||||
Name: entry.fileMetadata.Composer(),
|
||||
})
|
||||
}
|
||||
|
||||
rawValues := entry.fileMetadata.Raw()
|
||||
for k, v := range rawValues {
|
||||
str, ok := v.(string)
|
||||
if !ok {
|
||||
var number int
|
||||
number, ok = v.(int)
|
||||
if ok {
|
||||
str = fmt.Sprint(number)
|
||||
}
|
||||
}
|
||||
if ok && len(str) > 0 {
|
||||
if k == "mastering" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "mastering",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "lyricist" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "lyrics",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "guitar" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "performer, guitar",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "arrange" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "arranger",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "vocal" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "vocals",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "chorus" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "vocals",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "performer" {
|
||||
track.FileMetadata.Artists = append(track.FileMetadata.Artists, Name{
|
||||
Kind: "performer",
|
||||
Name: str,
|
||||
})
|
||||
}
|
||||
if k == "originaltitle" {
|
||||
track.FileMetadata.OriginalTitle = str
|
||||
}
|
||||
|
||||
value, exists := disc.CommonMetadata[k]
|
||||
if !exists {
|
||||
disc.CommonMetadata[k] = str
|
||||
} else if len(value) > 0 && value != str {
|
||||
disc.CommonMetadata[k] = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k := range disc.CommonMetadata {
|
||||
_, exists := rawValues[k]
|
||||
if !exists {
|
||||
disc.CommonMetadata[k] = ""
|
||||
}
|
||||
}
|
||||
|
||||
track.FileMetadata.Album = entry.fileMetadata.Album()
|
||||
track.FileMetadata.Title = entry.fileMetadata.Title()
|
||||
|
||||
|
@ -403,6 +497,78 @@ func HandleDiscEntry(panakoInstance *panako.Instance, pathEntry string) *DiscHan
|
|||
disc.Tracks = append(disc.Tracks, track)
|
||||
}
|
||||
|
||||
for k, v := range disc.CommonMetadata {
|
||||
if v == "" {
|
||||
delete(disc.CommonMetadata, k)
|
||||
}
|
||||
}
|
||||
|
||||
catno, ok := disc.CommonMetadata["catalogid"]
|
||||
if ok {
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "catalog",
|
||||
Name: catno,
|
||||
})
|
||||
}
|
||||
|
||||
album, ok := disc.CommonMetadata["TALB"] //ID3v2
|
||||
if ok {
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "album",
|
||||
Name: album,
|
||||
})
|
||||
disc.Album = album
|
||||
}
|
||||
|
||||
album, ok = disc.CommonMetadata["album"]
|
||||
if ok {
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "album",
|
||||
Name: album,
|
||||
})
|
||||
disc.Album = album
|
||||
}
|
||||
|
||||
discid, ok := disc.CommonMetadata["discid"]
|
||||
if ok {
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "discid",
|
||||
Name: discid,
|
||||
})
|
||||
}
|
||||
|
||||
cdtoc, ok := disc.CommonMetadata["cdtoc"]
|
||||
if ok {
|
||||
toc := TOC{}
|
||||
for _, v := range strings.Split(cdtoc, "+")[1:] {
|
||||
number, err := strconv.ParseInt(v, 16, 0)
|
||||
if err != nil {
|
||||
toc = TOC{}
|
||||
break
|
||||
}
|
||||
toc = append(toc, int(number))
|
||||
}
|
||||
if len(toc) > 0 {
|
||||
toc = append(TOC{toc[len(toc)-1]}, toc[0:len(toc)-1]...)
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "toc",
|
||||
Name: toc.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
catalogRE := regroup.MustCompile(`(?i)[\[\(\{](?P<catno>(?:[a-z]{2,}-?[0-9][a-z0-9\-~~]*)|(?:[0-9 ]{5,}))[\}\)\]]`)
|
||||
m := &struct {
|
||||
CatalogNumber string `regroup:"catno"`
|
||||
}{}
|
||||
err = catalogRE.MatchToTarget(disc.Directory, m)
|
||||
if err == nil {
|
||||
disc.Identifiers = append(disc.Identifiers, Name{
|
||||
Kind: "catalog",
|
||||
Name: strings.ReplaceAll(m.CatalogNumber, "~", "~"),
|
||||
})
|
||||
}
|
||||
|
||||
disc.TOC = append(TOC{disc.TOC[len(disc.TOC)-1]}, disc.TOC[0:len(disc.TOC)-1]...)
|
||||
|
||||
return disc
|
||||
|
|
Loading…
Reference in a new issue