Compare commits

..

2 Commits

5 changed files with 87 additions and 121 deletions

9
README.md Normal file
View File

@ -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
```

11
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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 New() (*Guessit, error) { func (g GuessitConfig) PipInstall() (err error) {
python3.PyErr_Clear() 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 err != nil {
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")
return return
} }
fmt.Println(string(cmdout))
item := python3.PyUnicode_FromString(s) return nil
defer item.DecRef() }
opts := python3.PyUnicode_FromString(strings.Join(options[:], " ")) func New(conf GuessitConfig) (Guessit, error) {
defer opts.DecRef() if conf.Python == "" {
conf.Python = "python3"
testdataPy := g.fn.CallFunctionObjArgs(item, opts) //retval: New reference
if !(testdataPy != nil && python3.PyErr_Occurred() == nil) {
return
} }
defer testdataPy.DecRef() pyPath, err := exec.LookPath(conf.Python)
if err != nil {
log.Fatal(err)
}
size := python3.PyDict_Size(testdataPy) conf.Python = pyPath
keys := python3.PyDict_Keys(testdataPy)
defer keys.DecRef()
vals := python3.PyDict_Values(testdataPy) if conf.Pip {
defer vals.DecRef() err = conf.PipInstall()
if err != nil {
tmpmap := make(map[string]interface{}) return Guessit{}, err
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 { return Guessit{conf}, nil
tmpmap["version"] = -1 }
}
config := &mapstructure.DecoderConfig{ func (g Guessit) Guessit(s string, options ...string) (out Match, err error) {
WeaklyTypedInput: true, args := []string{"-m", "guessit", s}
Result: &out, 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 { if err != nil {
return return
} }
err = decoder.Decode(tmpmap) err = json.Unmarshal(cmdout, &out)
if err != nil {
return
}
return return
} }

View File

@ -2,13 +2,18 @@ package guessit
import ( import (
"fmt" "fmt"
"log"
"testing" "testing"
) )
func TestGuessit(t *testing.T) { func TestGuessit(t *testing.T) {
g, err := New() g, err := New(GuessitConfig{
Git: false,
Pip: true,
})
if err != nil { if err != nil {
return log.Fatal(err)
} }
ss := []string{ ss := []string{
@ -22,6 +27,6 @@ func TestGuessit(t *testing.T) {
} }
for _, s := range ss { for _, s := range ss {
fmt.Println(g.Guessit(s)) //, "--excludes=season")) fmt.Println(g.Guessit(s, "--excludes=season"))
} }
} }