From 3739638ddf8c6c1fcc22360aded951929fe202c3 Mon Sep 17 00:00:00 2001 From: Unlock Music Dev Date: Mon, 5 Dec 2022 09:43:33 +0800 Subject: [PATCH] feat(qmc): use editorial distance to find the key --- algo/qmc/key_mmkv.go | 41 ++++++++++++++++++++++++++++++++++------- algo/qmc/qmc.go | 2 +- go.mod | 14 ++++++++------ go.sum | 19 ++++++++++++++----- 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/algo/qmc/key_mmkv.go b/algo/qmc/key_mmkv.go index 72b3815..81f891a 100644 --- a/algo/qmc/key_mmkv.go +++ b/algo/qmc/key_mmkv.go @@ -8,7 +8,10 @@ import ( "runtime" "strings" + "github.com/hbollon/go-edlib" + "github.com/samber/lo" "go.uber.org/zap" + "golang.org/x/exp/slices" "unlock-music.dev/mmkv" ) @@ -47,11 +50,13 @@ func readKeyFromMMKV(file string, logger *zap.Logger) ([]byte, error) { logger.Debug("mmkv vault opened", zap.Strings("keys", streamKeyVault.Keys())) } + _, partName := filepath.Split(file) buf, err := streamKeyVault.GetBytes(file) - if err != nil { // fallback match filename only - _, partName := filepath.Split(file) - keys := streamKeyVault.Keys() - for _, key := range keys { + + if buf == nil { + filePaths := streamKeyVault.Keys() + + for _, key := range filePaths { // fallback 1: match filename only if !strings.HasSuffix(key, partName) { continue } @@ -60,9 +65,31 @@ func readKeyFromMMKV(file string, logger *zap.Logger) ([]byte, error) { logger.Warn("read key from mmkv", zap.String("key", key), zap.Error(err)) } } - // TODO: use editorial judgement to select the best match - // since MacOS may change some characters in the file name. - // eg. "ぜ" -> "ぜ" + + if buf == nil { // fallback 2: match filename with edit distance + // use editorial judgement to select the best match + // since macOS may change some characters in the file name. + // e.g. "ぜ"(e3 81 9c) -> "ぜ"(e3 81 9b e3 82 99) + fileNames := lo.Map(filePaths, func(filePath string, _ int) string { + _, name := filepath.Split(filePath) + return name + }) + + minDisStr, err := edlib.FuzzySearch(partName, fileNames, edlib.Levenshtein) + if err != nil { + logger.Warn("fuzzy search failed", zap.Error(err)) + } + + // TODO: make distance configurable + // for now, assume only 1 character changed to 2 characters + if edlib.LevenshteinDistance(partName, minDisStr) < 3 { + idx := slices.Index(fileNames, minDisStr) + buf, err = streamKeyVault.GetBytes(filePaths[idx]) + if err != nil { + logger.Warn("read key from mmkv", zap.String("key", minDisStr), zap.Error(err)) + } + } + } } if len(buf) == 0 { diff --git a/algo/qmc/qmc.go b/algo/qmc/qmc.go index a775069..9d4002e 100644 --- a/algo/qmc/qmc.go +++ b/algo/qmc/qmc.go @@ -111,7 +111,7 @@ func (d *Decoder) searchKey() (err error) { fileSize := int(fileSizeM4) + 4 //goland:noinspection GoBoolExpressions - if runtime.GOOS == "darwin" { + if runtime.GOOS == "darwin" && !strings.HasPrefix(d.params.Extension, ".qmc") { d.decodedKey, err = readKeyFromMMKV(d.params.FilePath, d.logger) if err == nil { d.audioLen = fileSize diff --git a/go.mod b/go.mod index 9726bea..cbd1ab6 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,23 @@ module unlock-music.dev/cli -go 1.17 +go 1.19 require ( - github.com/urfave/cli/v2 v2.23.5 - go.uber.org/zap v1.23.0 + github.com/hbollon/go-edlib v1.6.0 + github.com/samber/lo v1.36.0 + github.com/urfave/cli/v2 v2.23.6 + go.uber.org/zap v1.24.0 golang.org/x/crypto v0.3.0 - google.golang.org/protobuf v1.28.1 + golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb unlock-music.dev/mmkv v0.0.0-20221204231432-41a75bd29939 ) require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/golang/protobuf v1.5.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb // indirect + google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 7d99469..4a019ce 100644 --- a/go.sum +++ b/go.sum @@ -6,19 +6,28 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/hbollon/go-edlib v1.6.0 h1:ga7AwwVIvP8mHm9GsPueC0d71cfRU/52hmPJ7Tprv4E= +github.com/hbollon/go-edlib v1.6.0/go.mod h1:wnt6o6EIVEzUfgbUZY7BerzQ2uvzp354qmS2xaLkrhM= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw= +github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/urfave/cli/v2 v2.23.5 h1:xbrU7tAYviSpqeR3X4nEFWUdB/uDZ6DE+HxmRU7Xtyw= github.com/urfave/cli/v2 v2.23.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.23.6 h1:iWmtKD+prGo1nKUtLO0Wg4z9esfBM4rAV4QRLQiEmJ4= +github.com/urfave/cli/v2 v2.23.6/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -29,20 +38,20 @@ go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb h1:QIsP/NmClBICkqnJ4rSIhnrGiGR7Yv9ZORGGnmmLTPk= golang.org/x/exp v0.0.0-20221204150635-6dcec336b2bb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -unlock-music.dev/mmkv v0.0.0-20221204144229-a40e4e5b9eca h1:21+n7CN+qrUiWbvHhIiewlUibXBldKREPXjQILyw5lE= -unlock-music.dev/mmkv v0.0.0-20221204144229-a40e4e5b9eca/go.mod h1:N+XdSYGbQs3PIt8k/kzFuTUO5YIal9da1mpK3ul6zJE= unlock-music.dev/mmkv v0.0.0-20221204231432-41a75bd29939 h1:qWv734RbYjIHtHhZSRbdSyAEJ5K1rWcPSuUOen86tvI= unlock-music.dev/mmkv v0.0.0-20221204231432-41a75bd29939/go.mod h1:1+Hdsrk8gl1i4/oxOnAhx6y51DAcUfi2CDni6Qhk8Kw=