diff --git a/README.md b/README.md new file mode 100644 index 0000000..a926ffb --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# guessit-go + +``` +python3 -m pip install -U nuitka + +git clone https://github.com/guessit-io/guessit.git + +nuitka3 --output-filename=guessit /path/to/guessit +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 30ec509..13b138a 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,11 @@ module git.stein-ivar.net/steino/guessit-go -go 1.17 +go 1.20 + +require github.com/mitchellh/mapstructure v1.4.2 require ( - git.stein-ivar.net/steino/cpy3 v3.8.0+incompatible - github.com/mitchellh/mapstructure v1.4.2 + git.stein-ivar.net/steino/cpy3 v0.0.0-20230524083048-7d65f97b9fa8 // indirect + 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 diff --git a/go.sum b/go.sum index 773360e..308786f 100644 --- a/go.sum +++ b/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/go.mod h1:jDKy1+hHkC3cWb9ZpIoLDwhZTAhEqP3IVNcgvndmQEQ= 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/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/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/guessit.go b/guessit.go index e73a8f8..69d07b1 100644 --- a/guessit.go +++ b/guessit.go @@ -1,148 +1,95 @@ package guessit -// #cgo pkg-config: python-3.9-embed -// #include -// import "C" import ( + "encoding/json" "fmt" - "os" - "strings" + "log" + "os/exec" - python3 "git.stein-ivar.net/steino/cpy3" - - "github.com/mitchellh/mapstructure" + _ "embed" ) -type Match struct { - // Main - Type string `mapstructure:"type,omitempty"` - Title string `mapstructure:"title,omitempty"` - 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 GuessitConfig struct { + Python string + Git bool + Pip bool } type Guessit struct { - fn *python3.PyObject + GuessitConfig } -func init() { - python3.Py_Initialize() - if !python3.Py_IsInitialized() { - fmt.Println("Error initializing the python interpreter") - os.Exit(1) - } +type Match struct { + // Main + Type string `json:"type,omitempty"` + Title string `json:"title,omitempty"` + 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 New() (*Guessit, error) { - python3.PyErr_Clear() +func (g GuessitConfig) PipInstall() (err error) { + args := []string{"-m", "pip", "install", "guessit3"} + cmd := exec.Command(g.Python, args...) + cmdout, err := cmd.Output() - 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) { - python3.PyErr_Clear() - - if len(s) == 0 { - err = fmt.Errorf("input string is empty") + if err != nil { return } + fmt.Println(string(cmdout)) - item := python3.PyUnicode_FromString(s) - defer item.DecRef() + return nil +} - 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 +func New(conf GuessitConfig) (Guessit, error) { + if conf.Python == "" { + conf.Python = "python3" } - defer testdataPy.DecRef() + pyPath, err := exec.LookPath(conf.Python) + if err != nil { + log.Fatal(err) + } - size := python3.PyDict_Size(testdataPy) - keys := python3.PyDict_Keys(testdataPy) - defer keys.DecRef() + conf.Python = pyPath - 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 conf.Pip { + err = conf.PipInstall() + if err != nil { + return Guessit{}, err } } - if _, ok := tmpmap["version"]; !ok { - tmpmap["version"] = -1 - } + return Guessit{conf}, nil +} - config := &mapstructure.DecoderConfig{ - WeaklyTypedInput: true, - Result: &out, - } +func (g Guessit) Guessit(s string, options ...string) (out Match, err error) { + args := []string{"-m", "guessit", s} + args = append(args, options...) + args = append(args, "--json") - decoder, err := mapstructure.NewDecoder(config) + cmd := exec.Command(g.Python, args...) + cmdout, err := cmd.Output() if err != nil { return } - err = decoder.Decode(tmpmap) - if err != nil { - return - } + err = json.Unmarshal(cmdout, &out) return } diff --git a/guessit_test.go b/guessit_test.go index 3b8d705..add76e6 100644 --- a/guessit_test.go +++ b/guessit_test.go @@ -2,13 +2,18 @@ package guessit import ( "fmt" + "log" "testing" ) func TestGuessit(t *testing.T) { - g, err := New() + g, err := New(GuessitConfig{ + Git: false, + Pip: true, + }) + if err != nil { - return + log.Fatal(err) } ss := []string{ @@ -22,6 +27,6 @@ func TestGuessit(t *testing.T) { } for _, s := range ss { - fmt.Println(g.Guessit(s)) //, "--excludes=season")) + fmt.Println(g.Guessit(s, "--excludes=season")) } }