Add missing files
This commit is contained in:
parent
9452aaf8d4
commit
7ffc6c7712
@ -0,0 +1,18 @@
|
|||||||
|
volumes:
|
||||||
|
mmm-db:
|
||||||
|
|
||||||
|
services:
|
||||||
|
mmm:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
db:
|
||||||
|
image: library/postgres:15
|
||||||
|
container_name: mmm-postgres
|
||||||
|
restart: no
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: mmm
|
||||||
|
POSTGRES_PASSWORD: mmm
|
||||||
|
volumes:
|
||||||
|
- mmm-db:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
173
main.go
173
main.go
@ -1,5 +1,178 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.m3d.pw/majomi/mmm/internal/db"
|
||||||
|
"github.com/dhowden/tag"
|
||||||
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type app struct{}
|
||||||
|
|
||||||
|
type FileScanner struct {
|
||||||
|
path string
|
||||||
|
ch chan string
|
||||||
|
stop chan struct{}
|
||||||
|
q db.Querier
|
||||||
|
d time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type MusicFile struct {
|
||||||
|
path string
|
||||||
|
tags tag.Metadata
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
musicPath, ok := os.LookupEnv("MMM_DIR")
|
||||||
|
if !ok {
|
||||||
|
log.Fatal("MMM_DIR not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
dsn, ok := os.LookupEnv("MMM_DB")
|
||||||
|
if !ok {
|
||||||
|
log.Fatal("MMM_DB not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
pool, err := pgxpool.New(context.Background(), dsn)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
q := db.New(pool)
|
||||||
|
|
||||||
|
scanner := NewFileScanner(musicPath, q, time.Hour)
|
||||||
|
scanner.Scan()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewFileScanner(path string, q db.Querier, d time.Duration) *FileScanner {
|
||||||
|
return &FileScanner{path: path, ch: make(chan string), stop: make(chan struct{}), q: q, d: d}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileScanner) Scan() {
|
||||||
|
go f.walkDir()
|
||||||
|
for path := range f.ch {
|
||||||
|
go func() {
|
||||||
|
exists, err := f.q.Exists(context.Background(), path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, err := tag.ReadFrom(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m := MusicFile{
|
||||||
|
path: path,
|
||||||
|
tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Adding to DB: %s: %+v", m.path, m.tags.Title())
|
||||||
|
|
||||||
|
track, err := f.q.AddTrack(context.Background(), db.AddTrackParams{
|
||||||
|
Path: m.path,
|
||||||
|
AlbumArtist: m.tags.AlbumArtist(),
|
||||||
|
Title: m.tags.Title(),
|
||||||
|
Album: m.tags.Album(),
|
||||||
|
Year: int32(m.tags.Year()),
|
||||||
|
Artist: m.tags.Artist(),
|
||||||
|
Genre: m.tags.Genre(),
|
||||||
|
Lyrics: m.tags.Lyrics(),
|
||||||
|
Composer: m.tags.Composer(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Added ", track.Title)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileScanner) walkDir() {
|
||||||
|
defer close(f.ch)
|
||||||
|
ticker := time.NewTicker(f.d)
|
||||||
|
|
||||||
|
// Create walk function, so we can use it right when we start and don't need to wait for the ticker to tick
|
||||||
|
walk := func() {
|
||||||
|
filepath.WalkDir(f.path, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if d.IsDir() || filepath.Ext(path) != ".flac" {
|
||||||
|
slog.Debug("skipping directory: ", path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
f.ch <- path
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
go walk()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
go walk()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileScanner) addToDB(path string) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, err := tag.ReadFrom(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Adding to DB: ", tags.Title())
|
||||||
|
}
|
||||||
|
|
||||||
|
func index(path string, wg *sync.WaitGroup) <-chan string {
|
||||||
|
fileChan := make(chan string)
|
||||||
|
go func(wg *sync.WaitGroup) {
|
||||||
|
filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if d.IsDir() || filepath.Ext(path) != ".flac" {
|
||||||
|
slog.Debug("skipping directory: ", path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fileChan <- path
|
||||||
|
wg.Add(1)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
close(fileChan)
|
||||||
|
}(wg)
|
||||||
|
return fileChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func readTag(path string, wg *sync.WaitGroup) {
|
||||||
|
wg.Add(1)
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
slog.Debug("reading tag", "path", path)
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
slog.Warn("failed to open file: ", path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
tags, err := tag.ReadFrom(f)
|
||||||
|
if err != nil {
|
||||||
|
slog.Warn("failed to parse file", "path", path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slog.Debug("tags", "title", tags.Title())
|
||||||
|
}
|
||||||
|
26
table.sql
26
table.sql
@ -0,0 +1,26 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS track
|
||||||
|
(
|
||||||
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
path TEXT UNIQUE,
|
||||||
|
album_artist TEXT,
|
||||||
|
title TEXT,
|
||||||
|
album TEXT,
|
||||||
|
disc INTEGER,
|
||||||
|
year INTEGER,
|
||||||
|
artist TEXT[],
|
||||||
|
genre TEXT,
|
||||||
|
lyrics TEXT,
|
||||||
|
composer TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS album
|
||||||
|
(
|
||||||
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
path TEXT UNIQUE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS artist
|
||||||
|
(
|
||||||
|
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
path TEXT UNIQUE
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user