Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata API #28

Open
wants to merge 7 commits into
base: non-admin-users
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions src/fs/cache.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package main

import (
"encoding/json"
"fmt"
"github.com/dhowden/tag"
"github.com/disintegration/imaging"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -32,11 +35,69 @@ func thumbnailer(imagePath string, savePath string) error {
return nil
}

func cacheMetadataPicture(mediaPath string, savePathPrefix string) error {
f, err := os.Open(mediaPath)
if err != nil {
log("error opening file: %s", mediaPath)
return err
}
t, err := tag.ReadFrom(f)
if err != nil {
log(`Error fetching metadata for file: "%s". Error is: "%s"`, mediaPath, err.Error())
return err
}

if pic := t.Picture(); pic != nil && pic.MIMEType != "" {
fmt.Println("File path: ", mediaPath)
json.NewEncoder(os.Stdout).Encode(pic)
for k, v := range EncodingMap {
if v == pic.MIMEType {
savePath := savePathPrefix + k
err = os.MkdirAll(filepath.Dir(savePath), os.ModePerm)
if err != nil {
log(`Error creating parent directory for file: "%s". Error is: "%s"`, savePath, err.Error())
return err
}
err = ioutil.WriteFile(savePath, pic.Data, os.ModePerm)
if err != nil {
log(`Error saving image thumbnail for file at location: "%s". Error is: "%s"`, savePath, err.Error())
return err
}
log("Thumbnail image saved for file: %s", mediaPath)
return nil
}
}
}
log("Thumbnail image not found for file: %s", mediaPath)
return nil
}

func fillCache(root string) error {
filepath.Walk(root, fillCacheWalkFunc)
return nil
}

func getThumbnailPath(path string) string {
parentDir := filepath.Dir(path)
filename := filepath.Base(path)
thumbnailDirPath := filepath.Join(parentDir, ".fscache/thumbnails")
thumbnailPath := filepath.Join(thumbnailDirPath, filename)
_, err := os.Stat(thumbnailPath)
if os.IsNotExist(err) {
files, err := ioutil.ReadDir(thumbnailDirPath)
if err == nil {
for _, f := range files {
fmt.Println(f.Name())
if strings.Contains(f.Name(), filename) {
thumbnailPath = filepath.Join(thumbnailDirPath, f.Name())
break
}
}
}
}
return thumbnailPath
}

func fillCacheWalkFunc(path string, info os.FileInfo, err error) error {
defer func() {
if v := recover(); v != nil {
Expand All @@ -48,16 +109,14 @@ func fillCacheWalkFunc(path string, info os.FileInfo, err error) error {
return nil
}
if ! info.IsDir() {
parentDir := filepath.Dir(path)
filename := filepath.Base(path)

thumbnailDirPath := filepath.Join(parentDir, ".fscache/thumbnails")
thumbnailPath := filepath.Join(thumbnailDirPath, filename)
thumbnailPath := getThumbnailPath(path)
thumbnailInfo, err := os.Stat(thumbnailPath)
if os.IsNotExist(err) || info.ModTime().After(thumbnailInfo.ModTime()) {
contentType := getContentType(path)
if strings.Contains(contentType, "image") {
thumbnailer(path, thumbnailPath)
} else {
cacheMetadataPicture(path, thumbnailPath)
}
}
} else {
Expand Down
158 changes: 78 additions & 80 deletions src/fs/file_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,8 @@ func (f *fileCacheInfo) invalidateCache() {
}

func (f *fileCacheInfo) fillCache(filePath, share, path string) {
parentDir := filepath.Dir(filePath)
filename := filepath.Base(filePath)

thumbnailDirPath := filepath.Join(parentDir, ".fscache/thumbnails")
thumbnailPath := filepath.Join(thumbnailDirPath, filename)
thumbnailPath := getThumbnailPath(filePath)
thumbnailInfo, err := os.Stat(thumbnailPath)
if os.IsNotExist(err) {
f.status = false
Expand Down Expand Up @@ -152,89 +149,90 @@ func dirToJSON(osFile *os.File, fullPath, share, path string) (string, error) {
return result, nil
}

var EncodingMap = map[string]string{
".pdf": "application/pdf",
".ogx": "application/ogg",
".anx": "application/annodex",
".txt": "text/plain",
".jpg": "image/jpg",
".jpeg": "image/jpeg",
".tif": "image/tiff",
".tiff": "image/tiff",
".png": "image/png",
".svg": "image/svg+xml",
".mp3": "audio/mpeg",
".aac": "audio/aac",
".oga": "audio/ogg",
".ogg": "audio/ogg",
".spx": "audio/ogg",
".wav": "audio/vnd.wave",
".flac": "audio/flac",
".axa": "audio/annodex",
".m4a": "audio/mp4",
".mka": "audio/x-matroska",
".axv": "video/annodex",
".ogv": "video/ogg",
".mov": "video/quicktime",
".mkv": "video/x-matroska",
".mk3d": "video/x-matroska-3d",
".mp4": "video/mp4",
".m4v": "video/x-m4v",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".ts": "video/mpeg",
".avi": "video/divx",
".qt": "video/quicktime",
".wmv": "video/x-ms-wmv",
".wtv": "video/x-ms-wtv",
".flv": "video/x-flv",
".3gp": "video/3gpp",
".webm": "video/webm",
".epub": "application/epub+zip",
".mobi": "application/x-mobipocket",
".zip": "application/zip",
".doc": "application/msword",
".dot": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
".docm": "application/vnd.ms-word.document.macroEnabled.12",
".dotm": "application/vnd.ms-word.template.macroEnabled.12",
".xls": "application/vnd.ms-excel",
".xlt": "application/vnd.ms-excel",
".xla": "application/vnd.ms-excel",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
".xltm": "application/vnd.ms-excel.template.macroEnabled.12",
".xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
".ppt": "application/vnd.ms-powerpoint",
".pot": "application/vnd.ms-powerpoint",
".pps": "application/vnd.ms-powerpoint",
".ppa": "application/vnd.ms-powerpoint",
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
".potm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
".html": "text/html",
".htm": "text/html",
".csv": "text/csv",
// subtitle stuff, with others below
".srt": "application/x-subrip",
".sub": "text/vnd.dvb.subtitle",
}

func getContentType(fileName string) string {
encodingMap := map[string]string{
".pdf": "application/pdf",
".ogx": "application/ogg",
".anx": "application/annodex",
".txt": "text/plain",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".tif": "image/tiff",
".tiff": "image/tiff",
".png": "image/png",
".svg": "image/svg+xml",
".mp3": "audio/mpeg",
".aac": "audio/aac",
".oga": "audio/ogg",
".ogg": "audio/ogg",
".spx": "audio/ogg",
".wav": "audio/vnd.wave",
".flac": "audio/flac",
".axa": "audio/annodex",
".m4a": "audio/mp4",
".mka": "audio/x-matroska",
".axv": "video/annodex",
".ogv": "video/ogg",
".mov": "video/quicktime",
".mkv": "video/x-matroska",
".mk3d": "video/x-matroska-3d",
".mp4": "video/mp4",
".m4v": "video/x-m4v",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".ts": "video/mpeg",
".avi": "video/divx",
".qt": "video/quicktime",
".wmv": "video/x-ms-wmv",
".wtv": "video/x-ms-wtv",
".flv": "video/x-flv",
".3gp": "video/3gpp",
".webm": "video/webm",
".epub": "application/epub+zip",
".mobi": "application/x-mobipocket",
".zip": "application/zip",
".doc": "application/msword",
".dot": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
".docm": "application/vnd.ms-word.document.macroEnabled.12",
".dotm": "application/vnd.ms-word.template.macroEnabled.12",
".xls": "application/vnd.ms-excel",
".xlt": "application/vnd.ms-excel",
".xla": "application/vnd.ms-excel",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
".xltm": "application/vnd.ms-excel.template.macroEnabled.12",
".xlam": "application/vnd.ms-excel.addin.macroEnabled.12",
".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
".ppt": "application/vnd.ms-powerpoint",
".pot": "application/vnd.ms-powerpoint",
".pps": "application/vnd.ms-powerpoint",
".ppa": "application/vnd.ms-powerpoint",
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12",
".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
".potm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
".html": "text/html",
".htm": "text/html",
".csv": "text/csv",
// subtitle stuff, with others below
".srt": "application/x-subrip",
".sub": "text/vnd.dvb.subtitle",
}

subExtensions := []string{".idx", ".sub", ".srt", ".ssa", ".ass", ".smi", ".utf", ".utf8", ".utf-8", ".rt", ".aqt", ".usf", ".jss", ".cdg", ".psb", ".mpsub", ".mpl2", ".pjs", ".dks", ".stl", ".vtt"}
for _, e := range subExtensions {
encodingMap[e] = "application/x-subtitle"
EncodingMap[e] = "application/x-subtitle"
}

extension := filepath.Ext(fileName)
result := encodingMap[strings.ToLower(extension)]
result := EncodingMap[strings.ToLower(extension)]

if result == "" {
result = "application/octet-stream"
Expand Down
49 changes: 49 additions & 0 deletions src/fs/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"github.com/dhowden/tag"
"os"
)

type Metadata struct {
Format string `json:"format"`
FileType string `json:"file_type"`
Title string `json:"title"`
Album string `json:"album"`
Artist string `json:"artist"`
AlbumArtist string `json:"album_artist"`
Composer string `json:"composer"`
Genre string `json:"genre"`
Year int `json:"year"`
Lyrics string `json:"lyrics"`
Comment string `json:"comment"`
}

func getMetadata(t tag.Metadata) (*Metadata) {
m := &Metadata{
Format: string(t.Format()),
FileType: string(t.FileType()),
Title: string(t.Title()),
Album: string(t.Album()),
Artist: string(t.Artist()),
AlbumArtist: string(t.AlbumArtist()),
Composer: string(t.Composer()),
Genre: string(t.Genre()),
Year: int(t.Year()),
Lyrics: string(t.Lyrics()),
Comment: string(t.Comment()),
}
return m
}

func getMetadataFromPath(path string) (*Metadata, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
t, err := tag.ReadFrom(f)
if err != nil {
return nil, err
}
return getMetadata(t), nil
}
Loading