Skip to content

Commit

Permalink
Merge pull request #9 from rbtr/trakt
Browse files Browse the repository at this point in the history
Add Trakt Collector output plugin
  • Loading branch information
rbtr authored Mar 10, 2020
2 parents b02178a + 2ed4231 commit f614010
Show file tree
Hide file tree
Showing 35 changed files with 777 additions and 286 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ pachinko*
.vscode
.pachinko.yaml
!docs/**/*
trakt
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ build: #vendor ## build
-o bin/$(MODULE) ./

clean: ## clean workspace
@rm -rf ./bin ./pachinko
@rm -rf ./bin ./$(MODULE)

help: ## print this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ other datastore types planned include : s3 (and whatever you would like to contr
pachinko currently supports these outputs:
- local filesystem (`path_mover`)
- stdout (`logger`)
- [trakt collector (`trakt_collector`)](docs/plugins/outputs/trakt.md)

#### processors
pachinko has the following required processors:
Expand Down
34 changes: 17 additions & 17 deletions cmd/config.go → cmd/genconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,51 @@ import (
"gopkg.in/yaml.v2"
)

// configCmd represents the config command
var configCmd = &cobra.Command{
Use: "config",
// genconf represents the config command
var genconf = &cobra.Command{
Use: "genconf",
Short: "Generate pachinko configs",
Long: `
Use this command to generate pachinko configs.
With no arguments, the config generated will contain the default
configs for every compiled plug-in.
$ pachinko config > config.yaml
$ pachinko genconf > config.yaml
Note: the generated config is always in alphabetical order of keys.
If order matters to pipeline plug-in execution, it will need
to be reordered after generation.
The config can be output as either yaml (default) or toml.
$ pachinko config -o toml > config.toml
$ pachinko genconf -o toml > config.toml
To only generate stubs for a subset of plug-ins, pass the plug-in
names as a comma separated list to the flag of their type.
$ pachinko config --inputs=path --processors=tvid,movid > config.yaml
$ pachinko genconf --inputs=path --processors=tvid,movid > config.yaml
The common flags (dry-run, logging) will be automatically set in the
output config when they are used on the config command.
$ pachinko config --log-level=debug > config.yaml
$ pachinko genconf --log-level=debug > config.yaml
The config file can then be edited and to fully customize the plug-ins
and the pachinko pipeline.
`,
Run: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.TraceLevel)
cfg, err := config.LoadCmdConfig()
cfg, err := config.LoadGenconf(rootCtx)
if err != nil {
log.Fatal(err)
}
if err := cfg.Validate(); err != nil {
log.Fatal(err)
}
pipelineCfg := config.NewCmdSort()
if err := cfg.DefaultConfig(pipelineCfg); err != nil {
sortCfg := config.NewSort(rootCtx)
if err := cfg.DefaultConfig(sortCfg); err != nil {
log.Fatal(err)
}

var out map[string]interface{}
if err := mapstructure.Decode(pipelineCfg, &out); err != nil {
if err := mapstructure.Decode(sortCfg, &out); err != nil {
log.Fatal(err)
}

Expand All @@ -84,12 +84,12 @@ and the pachinko pipeline.
}

func init() {
rootCmd.AddCommand(configCmd)
configCmd.Flags().StringP("format", "o", "yaml", "config output format")
configCmd.Flags().StringSlice("inputs", []string{}, "comma-separated list of input plugins")
configCmd.Flags().StringSlice("outputs", []string{}, "comma-separated list of output plugins")
configCmd.Flags().StringSlice("processors", []string{}, "comma-separated list of processor plugins")
if err := viper.BindPFlags(configCmd.Flags()); err != nil {
root.AddCommand(genconf)
genconf.Flags().StringP("format", "o", "yaml", "config output format")
genconf.Flags().StringSlice("inputs", []string{}, "comma-separated list of input plugins")
genconf.Flags().StringSlice("outputs", []string{}, "comma-separated list of output plugins")
genconf.Flags().StringSlice("processors", []string{}, "comma-separated list of processor plugins")
if err := viper.BindPFlags(genconf.Flags()); err != nil {
log.Fatal(err)
}
}
22 changes: 11 additions & 11 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
var cfgFile string
var rootCtx context.Context

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
// root represents the base command when called without any subcommands
var root = &cobra.Command{
Use: "pachinko",
Long: `
_ _ _
Expand All @@ -40,21 +40,21 @@ pluggable media sorter`,
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
if err := root.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

func init() {
cobra.OnInitialize(initConfig)
cobra.OnInitialize(rootConfig)

// bind flags
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.pachinko.yaml)")
rootCmd.PersistentFlags().Bool("dry-run", false, "run pipeline as read only and do not make changes")
rootCmd.PersistentFlags().StringP("log-level", "v", "info", "log verbosity (trace,debug,info,warn,error)")
rootCmd.PersistentFlags().String("log-format", "text", "log format (text,json)")
if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil {
// bind root flags
root.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.pachinko.yaml)")
root.PersistentFlags().Bool("dry-run", false, "run pipeline as read only and do not make changes")
root.PersistentFlags().StringP("log-level", "v", "info", "log verbosity (trace,debug,info,warn,error)")
root.PersistentFlags().String("log-format", "text", "log format (text,json)")
if err := viper.BindPFlags(root.PersistentFlags()); err != nil {
log.Fatal(err)
}

Expand All @@ -72,7 +72,7 @@ func init() {
}()
}

func initConfig() {
func rootConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
Expand Down
14 changes: 7 additions & 7 deletions cmd/sort.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ import (
"github.com/spf13/cobra"
)

// sortCmd represents the sort command
var sortCmd = &cobra.Command{
// sort represents the sort command
var sort = &cobra.Command{
Use: "sort",
Short: "Run the sorting pipeline.",
Long: `
Use this command to execute the sorting pipeline.
With no arguments, sort will load the config from %HOME/.pachinko.yaml.
With no arguments, sort will load the config from $HOME/.pachinko.yaml.
$ pachinko sort
If no config is provided, no plugins will be loaded and the pipeline will
not do anything useful.
`,
Run: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.TraceLevel)
cfg, err := config.LoadCmdSort()
sortConf, err := config.LoadSort(rootCtx)
if err != nil {
log.Fatal(err)
}
if err := cfg.Validate(); err != nil {
if err := sortConf.Validate(); err != nil {
log.Fatal(err)
}

p := pipeline.NewPipeline()
if err := cfg.ConfigurePipeline(p); err != nil {
if err := sortConf.ConfigurePipeline(p); err != nil {
log.Fatal(err)
}

Expand All @@ -49,5 +49,5 @@ not do anything useful.
}

func init() {
rootCmd.AddCommand(sortCmd)
root.AddCommand(sort)
}
84 changes: 84 additions & 0 deletions cmd/trakt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright © 2020 The Pachinko Authors
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package cmd

import (
"github.com/rbtr/pachinko/internal/config"
internaltrakt "github.com/rbtr/pachinko/internal/trakt"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var traktFile string

// trakt represents the config command
var trakt = &cobra.Command{
Use: "trakt",
Short: "Connect to Trakt",
Long: `
Use this command to connect Pachinko to Trakt.
Trakt requires that you connect and authorize Pachinko before it can make any
changes on your behalf.
This command will print a URL and code. Open the URL in your browser, sign in
to Trakt (if you aren't signed in already), and enter the code.
Pachinko will write the authorized credentials out to the file specified in
the "--authfile" flag. The credential is stored in a JSON notation:
{
"access-token": "[access-token]",
"client-id": "76a0c1e8d3331021f6e312115e27fe4c29f4ef23ef89a0a69143a62d136ab994",
"client-secret": "fe8d1f0921413028f92428d2922e13a728e27d2f35b26e315cf3dde31228568d",
"created": "[created-at]",
"expires": "7776000",
"refresh-token": "[refresh-token"
}
This credential file is portable and can be moved around with your
Pachinko install. Pachinko will automatically refresh it every 80 days during
normal operations.
The token expires after 90 days. If Pachinko can't refresh the token before
it expires, you will need to rerun this to generate a new authorization.
`,
Run: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.TraceLevel)
cfg, err := config.LoadTrakt(rootCtx)
if err != nil {
log.Fatal(err)
}
if err := cfg.Validate(); err != nil {
log.Fatal(err)
}
auth, err := internaltrakt.ReadAuthFile(cfg.Authfile)
if err != nil {
log.Fatal(err)
}
client, err := internaltrakt.NewTrakt(auth)
if err != nil {
log.Fatal(err)
}
if auth, err = client.Authorize(rootCtx); err != nil {
log.Fatal(err)
}
if err := internaltrakt.WriteAuthFile(cfg.Authfile, auth); err != nil {
log.Fatal(err)
}
},
}

func init() {
root.AddCommand(trakt)
trakt.Flags().StringVar(&traktFile, "authfile", internaltrakt.DefaultAuthfile, "where to save the trakt authorization credential")
trakt.Flags().BoolP("overwrite", "f", false, "overwrite the authfile if it exists already")
if err := viper.BindPFlags(trakt.Flags()); err != nil {
log.Fatal(err)
}
}
2 changes: 2 additions & 0 deletions docs/examples/pachinko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ outputs:
dry-run: false
name: path-mover
overwrite: false
- authfile: "/etc/pachinko/trakt"
name: trakt-collector
pipeline:
buffer: 10
processors:
Expand Down
1 change: 1 addition & 0 deletions docs/examples/trakt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"access-token":"xyz987","client-id":"76a0c1e8d3331021f6e312115e27fe4c29f4ef23ef89a0a69143a62d136ab994","client-secret":"fe8d1f0921413028f92428d2922e13a728e27d2f35b26e315cf3dde31228568d","created-at":"2020-01-02T03:04:05-00:00","expires-after":7776000000000000,"refresh-token":"abc123"}
32 changes: 32 additions & 0 deletions docs/plugins/outputs/trakt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
### Trakt and the Trakt Collector output
Pachinko can interact with Trakt. Currently, Pachinko can:
- add sorted items to your Trakt collection (`trakt_collector` output plugin)

#### Trakt Authorization
To communicate with Trakt, it needs an access token. A helper command is included for authorizating:
```bash
$ pachinko trakt
Authenticating in Trakt!
Please open in your browser: https://trakt.tv/activate
and enter the code: 1234A1AA
```

Enter the provided code at the [link](https://trakt.tv/activate) and Pachinko will receive an access token. It will write the access credentials out to a file, by default `/etc/pachinko/trakt`. Specify a different file by using the `--authfile /path/to/file` flag on the `trakt` command.

The [authfile](../../examples/trakt) is JSON and contains authorization credentials.

#### Trakt Collector
To add items to your Trakt collection when Pachinko is done processing them, enable the Trakt Collector output plugin in your Pachinko config file.

The only configurable option is the authfile location - point it at the authfile created by the authorization step as described [above](#trakt-authorization).

```yaml
#...
outputs:
- name: trakt-collector
authfile: "/etc/pachinko/trakt"

#...
```

Now when Pachinko identifies and processes TV or Movies they will be automatically collected in Trakt!
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ go 1.13

require (
github.com/BurntSushi/toml v0.3.1
github.com/cyruzin/golang-tmdb v1.2.1
github.com/cyruzin/golang-tmdb v1.3.1
github.com/lithammer/fuzzysearch v1.1.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.1.2
github.com/pkg/errors v0.9.1
github.com/rbtr/go-trakt v0.0.0-20200310010953-144101cfef69
github.com/rbtr/go-tvdb v0.0.0-20200127015222-6fcb5ef30e70
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/spf13/cobra v0.0.6
github.com/spf13/viper v1.6.2
gopkg.in/yaml.v2 v2.2.8
)
Loading

0 comments on commit f614010

Please sign in to comment.