Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sentriz committed Mar 29, 2019
0 parents commit e9c0f09
Show file tree
Hide file tree
Showing 527 changed files with 477,627 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.db
scanner
server
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

199 changes: 199 additions & 0 deletions cmd/scanner/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package main

import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strings"
"time"

"github.com/sentriz/gonic/db"
"github.com/sentriz/gonic/model"

"github.com/dhowden/tag"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/karrick/godirwalk"
)

var (
orm *gorm.DB
tx *gorm.DB
cLastAlbum = &lastAlbum{}
audioExtensions = map[string]bool{
".mp3": true,
".flac": true,
".aac": true,
".m4a": true,
}
coverFilenames = map[string]bool{
"cover.png": true,
"cover.jpg": true,
"cover.jpeg": true,
"folder.png": true,
"folder.jpg": true,
"folder.jpeg": true,
"album.png": true,
"album.jpg": true,
"album.jpeg": true,
"front.png": true,
"front.jpg": true,
"front.jpeg": true,
}
)

type lastAlbum struct {
coverModTime time.Time // 1st needed for cover insertion
coverPath string // 2rd needed for cover insertion
id string // 3nd needed for cover insertion
}

func (l *lastAlbum) isEmpty() bool {
return l.coverPath == ""
}

func isAudio(filename string) bool {
ext := strings.ToLower(filepath.Ext(filename))
_, ok := audioExtensions[ext]
return ok
}

func isCover(filename string) bool {
_, ok := coverFilenames[strings.ToLower(filename)]
return ok
}

func readTags(fullPath string) (tag.Metadata, error) {
trackData, err := os.Open(fullPath)
if err != nil {
return nil, fmt.Errorf("when tags from disk: %v\n", err)
}
defer trackData.Close()
tags, err := tag.ReadFrom(trackData)
if err != nil {
return nil, err
}
return tags, nil
}

func handleFolderCompletion(fullPath string, info *godirwalk.Dirent) error {
log.Printf("processed folder `%s`\n", fullPath)
if cLastAlbum.isEmpty() {
return nil
}
cover := model.Cover{
Path: cLastAlbum.coverPath,
}
err := tx.Where(cover).First(&cover).Error
if !gorm.IsRecordNotFoundError(err) &&
!cLastAlbum.coverModTime.After(cover.UpdatedAt) {
return nil
}
image, err := ioutil.ReadFile(cLastAlbum.coverPath)
if err != nil {
return fmt.Errorf("when reading cover: %v\n", err)
}
cover.Image = image
cover.AlbumID = cLastAlbum.id
tx.Save(&cover)
cLastAlbum = &lastAlbum{}
return nil
}

func processFile(fullPath string, info *godirwalk.Dirent) error {
if info.IsDir() {
return nil
}
stat, err := os.Stat(fullPath)
if err != nil {
return fmt.Errorf("when stating file: %v\n", err)
}
modTime := stat.ModTime()
_, filename := path.Split(fullPath)
if isCover(filename) {
cLastAlbum.coverModTime = modTime // 1st needed for cover insertion
cLastAlbum.coverPath = fullPath // 2nd needed for cover insertion
return nil
}
if !isAudio(filename) {
return nil
}
// set track basics
track := model.Track{
Path: fullPath,
}
err = tx.Where(track).First(&track).Error
if !gorm.IsRecordNotFoundError(err) && !modTime.After(track.UpdatedAt) {
return nil
}
tags, err := readTags(fullPath)
if err != nil {
return fmt.Errorf("when reading tags: %v\n", err)
}
trackNumber, totalTracks := tags.Track()
discNumber, TotalDiscs := tags.Disc()
track.Path = fullPath
track.Title = tags.Title()
track.DiscNumber = discNumber
track.TotalDiscs = TotalDiscs
track.TotalTracks = totalTracks
track.TrackNumber = trackNumber
track.Year = tags.Year()
// set artist
artist := model.Artist{
Name: tags.AlbumArtist(),
}
err = tx.Where(artist).First(&artist).Error
if gorm.IsRecordNotFoundError(err) {
artist.Name = tags.AlbumArtist()
tx.Save(&artist)
}
track.ArtistID = artist.ID
// set album
album := model.Album{
ArtistID: artist.ID,
Title: tags.Album(),
}
err = tx.Where(album).First(&album).Error
if gorm.IsRecordNotFoundError(err) {
album.Title = tags.Album()
album.ArtistID = artist.ID
tx.Save(&album)
}
track.AlbumID = album.ID
// set the _3rd_ variable for cover insertion.
// it will be used by the `handleFolderCompletion` function
cLastAlbum.id = album.ID
// save track
tx.Save(&track)
return nil
}

func main() {
if len(os.Args) != 2 {
log.Fatalf("usage: %s <path to music>", os.Args[0])
}
orm = db.New()
orm.SetLogger(log.New(os.Stdout, "gorm ", 0))
orm.AutoMigrate(
&model.Album{},
&model.Artist{},
&model.Track{},
&model.Cover{},
)
startTime := time.Now()
tx = orm.Begin()
err := godirwalk.Walk(os.Args[1], &godirwalk.Options{
Callback: processFile,
PostChildrenCallback: handleFolderCompletion,
Unsorted: true,
})
if err != nil {
log.Fatalf("error when walking: %v\n", err)
}
tx.Commit()
log.Printf("scanned in %s\n", time.Since(startTime))
}
21 changes: 21 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"log"

"github.com/sentriz/gonic/db"
"github.com/sentriz/gonic/handler"
"github.com/sentriz/gonic/router"
)

func main() {
d := db.New()
r := router.New()
h := &handler.Handler{
DB: d,
Router: r,
}
rest := r.Group("/rest")
rest.GET("", h.GetTest)
log.Fatal(r.Start("127.0.0.1:5001"))
}
16 changes: 16 additions & 0 deletions db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package db

import (
"log"

"github.com/jinzhu/gorm"
)

// New creates a new GORM connection to the database
func New() *gorm.DB {
db, err := gorm.Open("sqlite3", "gonic.db")
if err != nil {
log.Printf("when opening database: %v\n", err)
}
return db
}
27 changes: 27 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module github.com/sentriz/gonic

require (
cloud.google.com/go v0.37.1 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dhowden/tag v0.0.0-20181104225729-a9f04c2798ca
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/gofrs/uuid v3.2.0+incompatible // indirect
github.com/jinzhu/gorm v1.9.2
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect
github.com/jinzhu/now v1.0.0 // indirect
github.com/karrick/godirwalk v1.8.0
github.com/labstack/echo v3.3.10+incompatible
github.com/labstack/gommon v0.2.8 // indirect
github.com/lib/pq v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/mattn/go-sqlite3 v1.10.0 // indirect
github.com/myesui/uuid v1.0.0 // indirect
github.com/stretchr/testify v1.3.0 // indirect
github.com/twinj/uuid v1.0.0
github.com/valyala/fasttemplate v1.0.1 // indirect
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 // indirect
google.golang.org/appengine v1.5.0 // indirect
)
Loading

0 comments on commit e9c0f09

Please sign in to comment.