Use wchar_t for TagLib filenames on Windows (#1310)

* Use wchar_t for tagLib filenames on Windows

* Make TagLib default extractor for all platforms.

* Organize imports

Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
caiocotts 2021-08-28 19:35:54 -04:00 committed by GitHub
parent c55e65902b
commit 54f98497c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 122 additions and 18 deletions

View File

@ -214,7 +214,7 @@ func init() {
viper.SetDefault("reverseproxyuserheader", "Remote-User")
viper.SetDefault("reverseproxywhitelist", "")
viper.SetDefault("scanner.extractor", DefaultScannerExtractor)
viper.SetDefault("scanner.extractor", consts.DefaultScannerExtractor)
viper.SetDefault("scanner.genreseparators", ";/,")
viper.SetDefault("agents", "lastfm,spotify")

View File

@ -1,5 +0,0 @@
// +build !windows
package conf
const DefaultScannerExtractor = "taglib"

View File

@ -1,5 +0,0 @@
// +build windows
package conf
const DefaultScannerExtractor = "ffmpeg"

View File

@ -47,6 +47,8 @@ const (
PlaceholderAvatar = "logo-192x192.png"
DefaultHttpClientTimeOut = 10 * time.Second
DefaultScannerExtractor = "taglib"
)
// Cache options

View File

@ -10,13 +10,12 @@ import (
"strings"
"time"
"github.com/navidrome/navidrome/scanner/metadata/ffmpeg"
"github.com/navidrome/navidrome/scanner/metadata/taglib"
"github.com/google/uuid"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/scanner/metadata/ffmpeg"
"github.com/navidrome/navidrome/scanner/metadata/taglib"
)
type Parser interface {
@ -32,8 +31,8 @@ func Extract(files ...string) (map[string]Tags, error) {
p, ok := parsers[conf.Server.Scanner.Extractor]
if !ok {
log.Warn("Invalid 'Scanner.Extractor' option. Using default", "requested", conf.Server.Scanner.Extractor,
"validOptions", "ffmpeg,taglib", "default", conf.DefaultScannerExtractor)
p = parsers[conf.DefaultScannerExtractor]
"validOptions", "ffmpeg,taglib", "default", consts.DefaultScannerExtractor)
p = parsers[consts.DefaultScannerExtractor]
}
extractedTags, err := p.Parse(files...)

View File

@ -0,0 +1,9 @@
// +build !windows
package taglib
import "C"
func getFilename(s string) *C.char {
return C.CString(s)
}

View File

@ -0,0 +1,96 @@
// +build windows
package taglib
// From https://github.com/orofarne/gowchar
/*
#include <wchar.h>
const size_t SIZEOF_WCHAR_T = sizeof(wchar_t);
void gowchar_set (wchar_t *arr, int pos, wchar_t val)
{
arr[pos] = val;
}
wchar_t gowchar_get (wchar_t *arr, int pos)
{
return arr[pos];
}
*/
import "C"
import (
"fmt"
"unicode/utf16"
"unicode/utf8"
)
var SIZEOF_WCHAR_T C.size_t = C.size_t(C.SIZEOF_WCHAR_T)
func getFilename(s string) *C.wchar_t {
wstr, _ := StringToWcharT(s)
return wstr
}
func StringToWcharT(s string) (*C.wchar_t, C.size_t) {
switch SIZEOF_WCHAR_T {
case 2:
return stringToWchar2(s) // Windows
case 4:
return stringToWchar4(s) // Unix
default:
panic(fmt.Sprintf("Invalid sizeof(wchar_t) = %v", SIZEOF_WCHAR_T))
}
panic("?!!")
}
// Windows
func stringToWchar2(s string) (*C.wchar_t, C.size_t) {
var slen int
s1 := s
for len(s1) > 0 {
r, size := utf8.DecodeRuneInString(s1)
if er, _ := utf16.EncodeRune(r); er == '\uFFFD' {
slen += 1
} else {
slen += 2
}
s1 = s1[size:]
}
slen++ // \0
res := C.malloc(C.size_t(slen) * SIZEOF_WCHAR_T)
var i int
for len(s) > 0 {
r, size := utf8.DecodeRuneInString(s)
if r1, r2 := utf16.EncodeRune(r); r1 != '\uFFFD' {
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r1))
i++
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r2))
i++
} else {
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
i++
}
s = s[size:]
}
C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
return (*C.wchar_t)(res), C.size_t(slen)
}
// Unix
func stringToWchar4(s string) (*C.wchar_t, C.size_t) {
slen := utf8.RuneCountInString(s)
slen++ // \0
res := C.malloc(C.size_t(slen) * SIZEOF_WCHAR_T)
var i int
for len(s) > 0 {
r, size := utf8.DecodeRuneInString(s)
C.gowchar_set((*C.wchar_t)(res), C.int(i), C.wchar_t(r))
s = s[size:]
i++
}
C.gowchar_set((*C.wchar_t)(res), C.int(slen-1), C.wchar_t(0)) // \0
return (*C.wchar_t)(res), C.size_t(slen)
}

View File

@ -17,7 +17,11 @@
char has_cover(const TagLib::FileRef f);
#ifdef WIN32
int taglib_read(const wchar_t *filename, unsigned long id) {
#else
int taglib_read(const char *filename, unsigned long id) {
#endif
TagLib::FileRef f(filename, true, TagLib::AudioProperties::Fast);
if (f.isNull()) {

View File

@ -21,7 +21,7 @@ import (
)
func Read(filename string) (map[string][]string, error) {
fp := C.CString(filename)
fp := getFilename(filename)
defer C.free(unsafe.Pointer(fp))
id, m := newMap()
defer deleteMap(id)

View File

@ -8,7 +8,11 @@ extern "C" {
extern void go_map_put_str(unsigned long id, char *key, char *val);
extern void go_map_put_int(unsigned long id, char *key, int val);
#ifdef WIN32
int taglib_read(const wchar_t *filename, unsigned long id);
#else
int taglib_read(const char *filename, unsigned long id);
#endif
#ifdef __cplusplus
}