parent
51951bdda7
commit
e6aaace483
|
@ -0,0 +1,9 @@
|
||||||
|
# guessit-go
|
||||||
|
|
||||||
|
``` go
|
||||||
|
guessit, err := New(GuessitConfig{
|
||||||
|
Pip: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
match := guessit.Guessit("Treme.1x03.Right.Place,.Wrong.Time.HDTV.XviD-NoTV.avi")
|
||||||
|
```
|
11
go.mod
11
go.mod
|
@ -1,10 +1,11 @@
|
||||||
module git.stein-ivar.net/steino/guessit-go
|
module git.stein-ivar.net/steino/guessit-go
|
||||||
|
|
||||||
go 1.17
|
go 1.20
|
||||||
|
|
||||||
|
require github.com/mitchellh/mapstructure v1.4.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible
|
git.stein-ivar.net/steino/cpy3 v0.0.0-20230524083048-7d65f97b9fa8 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.2
|
github.com/justincormack/go-memfd v0.0.0-20170219213707-6e4af0518993 // indirect
|
||||||
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.7.0 // indirect
|
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,7 +1,11 @@
|
||||||
|
git.stein-ivar.net/steino/cpy3 v0.0.0-20230524083048-7d65f97b9fa8 h1:3wKFzSMTfDpqnjqr6oyPDsPrufRmC7PuVqJ6KzAdjwQ=
|
||||||
|
git.stein-ivar.net/steino/cpy3 v0.0.0-20230524083048-7d65f97b9fa8/go.mod h1:TUfV4l/zaEgFiclf97tC1i++NlQa/WYToI4VaYkNlJU=
|
||||||
git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible h1:Cv7VXH+Av7HPDIMFWMzCD7XjR0+IG5PRKxB/5KueTCM=
|
git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible h1:Cv7VXH+Av7HPDIMFWMzCD7XjR0+IG5PRKxB/5KueTCM=
|
||||||
git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible/go.mod h1:jDKy1+hHkC3cWb9ZpIoLDwhZTAhEqP3IVNcgvndmQEQ=
|
git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible/go.mod h1:jDKy1+hHkC3cWb9ZpIoLDwhZTAhEqP3IVNcgvndmQEQ=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/justincormack/go-memfd v0.0.0-20170219213707-6e4af0518993 h1:YnMJVKw7M5rE15UsVY7w2cnxcnArci7v1g3butq0YbI=
|
||||||
|
github.com/justincormack/go-memfd v0.0.0-20170219213707-6e4af0518993/go.mod h1:VYi8SD2j14Nh9hNT7l57A00YUx/tMxY6pPA1IGljdrg=
|
||||||
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||||
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
|
191
guessit.go
191
guessit.go
|
@ -1,148 +1,95 @@
|
||||||
package guessit
|
package guessit
|
||||||
|
|
||||||
// #cgo pkg-config: python-3.9-embed
|
|
||||||
// #include <Python.h>
|
|
||||||
// import "C"
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"log"
|
||||||
"strings"
|
"os/exec"
|
||||||
|
|
||||||
python3 "git.stein-ivar.net/steino/cpy3"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
type GuessitConfig struct {
|
||||||
// Main
|
Python string
|
||||||
Type string `mapstructure:"type,omitempty"`
|
Git bool
|
||||||
Title string `mapstructure:"title,omitempty"`
|
Pip bool
|
||||||
ReleaseGroup string `mapstructure:"release_group,omitempty"`
|
|
||||||
StreamingService string `mapstructure:"streaming_service,omitempty"`
|
|
||||||
|
|
||||||
// Episode
|
|
||||||
Season int64 `mapstructure:"season,omitempty"`
|
|
||||||
Episode int64 `mapstructure:"episode,omitempty"`
|
|
||||||
Version int64 `mapstructure:"version,omitempty"`
|
|
||||||
|
|
||||||
// Video
|
|
||||||
ScreenSize string `mapstructure:"screen_size,omitempty"`
|
|
||||||
Container string `mapstructure:"container,omitempty"`
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
AudioChannels string `mapstructure:"audio_channels,omitempty"`
|
|
||||||
AudioCodec []string `mapstructure:"audio_codec,omitempty"`
|
|
||||||
|
|
||||||
// Other
|
|
||||||
Other []string `mapstructure:"other,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Guessit struct {
|
type Guessit struct {
|
||||||
fn *python3.PyObject
|
GuessitConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
type Match struct {
|
||||||
python3.Py_Initialize()
|
// Main
|
||||||
if !python3.Py_IsInitialized() {
|
Type string `json:"type,omitempty"`
|
||||||
fmt.Println("Error initializing the python interpreter")
|
Title string `json:"title,omitempty"`
|
||||||
os.Exit(1)
|
ReleaseGroup string `json:"release_group,omitempty"`
|
||||||
|
StreamingService string `json:"streaming_service,omitempty"`
|
||||||
|
|
||||||
|
// Episode
|
||||||
|
Season int64 `json:"season,omitempty"`
|
||||||
|
Episode int64 `json:"episode,omitempty"`
|
||||||
|
Version int64 `json:"version,omitempty"`
|
||||||
|
|
||||||
|
// Video
|
||||||
|
ScreenSize string `json:"screen_size,omitempty"`
|
||||||
|
Container string `json:"container,omitempty"`
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
AudioChannels string `json:"audio_channels,omitempty"`
|
||||||
|
AudioCodec []string `json:"audio_codec,omitempty"`
|
||||||
|
|
||||||
|
// Other
|
||||||
|
Other []string `json:"other,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GuessitConfig) PipInstall() (err error) {
|
||||||
|
args := []string{"-m", "pip", "install", "guessit"}
|
||||||
|
cmd := exec.Command(g.Python, args...)
|
||||||
|
cmdout, err := cmd.Output()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(cmdout))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(conf GuessitConfig) (Guessit, error) {
|
||||||
|
if conf.Python == "" {
|
||||||
|
conf.Python = "python3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pyPath, err := exec.LookPath(conf.Python)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.Python = pyPath
|
||||||
|
|
||||||
|
if conf.Pip {
|
||||||
|
err = conf.PipInstall()
|
||||||
|
if err != nil {
|
||||||
|
return Guessit{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() (*Guessit, error) {
|
return Guessit{conf}, nil
|
||||||
python3.PyErr_Clear()
|
|
||||||
|
|
||||||
module := python3.PyImport_ImportModule("guessit") //ret val: new ref
|
|
||||||
if !(module != nil && python3.PyErr_Occurred() == nil) {
|
|
||||||
return nil, fmt.Errorf("failed to import module 'guessit'")
|
|
||||||
}
|
|
||||||
defer module.DecRef()
|
|
||||||
|
|
||||||
dict := python3.PyModule_GetDict(module) //ret val: Borrowed
|
|
||||||
if !(dict != nil && python3.PyErr_Occurred() == nil) {
|
|
||||||
return nil, fmt.Errorf("could not get dict for module")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := python3.PyDict_GetItemString(dict, "guessit") //retval: Borrowed
|
|
||||||
if !(fn != nil && python3.PyCallable_Check(fn)) {
|
|
||||||
return nil, fmt.Errorf("could not find function 'guessit'")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Guessit{
|
|
||||||
fn: fn,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Guessit) Guessit(s string, options ...string) (out Match, err error) {
|
func (g Guessit) Guessit(s string, options ...string) (out Match, err error) {
|
||||||
python3.PyErr_Clear()
|
args := []string{"-m", "guessit", s}
|
||||||
|
args = append(args, options...)
|
||||||
|
args = append(args, "--json")
|
||||||
|
|
||||||
if len(s) == 0 {
|
cmd := exec.Command(g.Python, args...)
|
||||||
err = fmt.Errorf("input string is empty")
|
cmdout, err := cmd.Output()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
item := python3.PyUnicode_FromString(s)
|
|
||||||
defer item.DecRef()
|
|
||||||
|
|
||||||
opts := python3.PyUnicode_FromString(strings.Join(options[:], " "))
|
|
||||||
defer opts.DecRef()
|
|
||||||
|
|
||||||
testdataPy := g.fn.CallFunctionObjArgs(item, opts) //retval: New reference
|
|
||||||
if !(testdataPy != nil && python3.PyErr_Occurred() == nil) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer testdataPy.DecRef()
|
|
||||||
|
|
||||||
size := python3.PyDict_Size(testdataPy)
|
|
||||||
keys := python3.PyDict_Keys(testdataPy)
|
|
||||||
defer keys.DecRef()
|
|
||||||
|
|
||||||
vals := python3.PyDict_Values(testdataPy)
|
|
||||||
defer vals.DecRef()
|
|
||||||
|
|
||||||
tmpmap := make(map[string]interface{})
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
kitem := python3.PyList_GetItem(keys, i)
|
|
||||||
key := python3.PyUnicode_AsUTF8(kitem)
|
|
||||||
kitem = nil
|
|
||||||
|
|
||||||
val := python3.PyList_GetItem(vals, i)
|
|
||||||
switch {
|
|
||||||
case python3.PyLong_Check(val):
|
|
||||||
tmpmap[key] = python3.PyLong_AsLongLong(val)
|
|
||||||
case python3.PyUnicode_Check(val):
|
|
||||||
tmpmap[key] = python3.PyUnicode_AsUTF8(val)
|
|
||||||
case python3.PyList_Check(val):
|
|
||||||
var tmp []string
|
|
||||||
for i := 0; i < python3.PyList_Size(val); i++ {
|
|
||||||
item := python3.PyList_GetItem(val, i)
|
|
||||||
v := python3.PyUnicode_AsUTF8(item)
|
|
||||||
tmp = append(tmp, v)
|
|
||||||
}
|
|
||||||
tmpmap[key] = tmp
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := tmpmap["version"]; !ok {
|
|
||||||
tmpmap["version"] = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &mapstructure.DecoderConfig{
|
|
||||||
WeaklyTypedInput: true,
|
|
||||||
Result: &out,
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder, err := mapstructure.NewDecoder(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = decoder.Decode(tmpmap)
|
err = json.Unmarshal(cmdout, &out)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,17 @@ package guessit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGuessit(t *testing.T) {
|
func TestGuessit(t *testing.T) {
|
||||||
g, err := New()
|
guessit, err := New(GuessitConfig{
|
||||||
|
Pip: true,
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := []string{
|
ss := []string{
|
||||||
|
@ -22,6 +26,6 @@ func TestGuessit(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range ss {
|
for _, s := range ss {
|
||||||
fmt.Println(g.Guessit(s)) //, "--excludes=season"))
|
fmt.Println(guessit.Guessit(s)) //, "--excludes=season"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue