Skip to content

Commit

Permalink
CLI: Create 'scan' subparser using Kong
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanConnell committed Dec 31, 2023
1 parent 1486106 commit 92ca660
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 79 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Theres a few things you'll need to set up before running this script.
You'll need to create a new Ticketmaster API token on [developer.ticketmaster.com](https://developer.ticketmaster.com)

### 2. Artists file
A file containing a list of artists (1 per line) that you want to be notified about will need to created and passed to the application via the `--artistFile` flag.
A file containing a list of artists (1 per line) that you want to be notified about will need to created and passed to the application via the `--artist-file` flag.

An example artist file might look something like the following:
```
Expand Down Expand Up @@ -58,6 +58,6 @@ docker run --rm -it \
-e TICKETMASTER_API_KEY=ticketmaster_api_key_goes_here \
-e DISCORD_WEBHOOK_URL=discord_webhook_url_goes_here \
ryanconnell/concert-watcher:latest \
sh -c '/bin/concert-watcher --apiKey=$TICKETMASTER_API_KEY --artistFile=/config/artists --ticketmasterConfig=/config/ticketmaster.yaml --discordWebhookURL=$DISCORD_WEBHOOK_URL'
sh -c '/bin/concert-watcher scan --api-key=$TICKETMASTER_API_KEY --artist-file=/config/artists --ticketmaster-config=/config/ticketmaster.yaml --discord-webhook-url=$DISCORD_WEBHOOK_URL'
```
Don't forget to replace the `ticketmaster_api_key_goes_here` and `discord_webhook_url_goes_here` with the values you generated in the above sections.
89 changes: 14 additions & 75 deletions cmd/watcher/main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package main

import (
"bufio"
"flag"
"fmt"
"log"
"os"
"sort"

"github.com/RyanConnell/concert-watcher/internal/watcher"
"github.com/RyanConnell/concert-watcher/pkg/ticketmaster"
"github.com/RyanConnell/concert-watcher/internal/commands"

"github.com/alecthomas/kong"
)

// CLI contains all of our parsers.
var CLI struct {
Scan commands.ScanCmd `cmd:"" help:"Scan Ticketmaster for matching events"`
}

type flags struct {
apiKey string
artistFile string
Expand All @@ -22,73 +23,11 @@ type flags struct {
}

func main() {
f := parseFlags()

// Ticketmaster will give us an authentication error if we don't have an API key.
if f.apiKey == "" {
log.Fatalf("Unable to run without a Ticketmaster API key. " +
"Please pass one via the --apiKey option")
return
}

// Read artists
artists, err := readLines(f.artistFile)
if err != nil {
log.Fatalf("Error reading file: %v", err)
return
}

reader := ticketmaster.NewReader(f.apiKey)
watcher := watcher.NewWatcher(reader, f.ticketmasterConfigFile, artists,
f.discordWebhookURL, f.diffFile)
events, err := watcher.FindEvents(f.diffMode)
if err != nil {
log.Fatalf("Error retrieving events: %v", err)
return
}

// Sort our events by date
sort.Slice(events, func(i, j int) bool {
return events[i].Date() < events[j].Date()
})
fmt.Printf("Found %d matching events\n", len(events))
for _, event := range events {
fmt.Printf("- %s\n", event.String())
}

if err := watcher.Notify(events); err != nil {
log.Fatalf("Error notifying discord: %v", err)
return
}
}

func parseFlags() *flags {
f := &flags{}
flag.StringVar(&f.apiKey, "apiKey", "", "Ticketmaster API Key")
flag.StringVar(&f.artistFile, "artistFile", "artists", "Path to a file containing a list of "+
"artists to search for")
flag.StringVar(&f.discordWebhookURL, "discordWebhookURL", "", "Discord webhook URL")
flag.StringVar(&f.ticketmasterConfigFile, "ticketmasterConfig", "ticketmaster.yaml",
"Path to a file containing search criteria for ticketmaster event lookups")
flag.BoolVar(&f.diffMode, "diff", false, "Run in diff mode which only notifies "+
"for events we haven't already seen.")
flag.StringVar(&f.diffFile, "diffFile", "previous-ids", "Path to a file that stores the list "+
"of events that we have previously sent notifications for")
flag.Parse()
return f
}

func readLines(fileName string) ([]string, error) {
file, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer file.Close()

scanner := bufio.NewScanner(file)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
ctx := kong.Parse(&CLI)
switch ctx.Command() {
case "scan":
CLI.Scan.Run()
default:
log.Fatalf("unknown command: %s", ctx.Command())
}
return lines, nil
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/RyanConnell/concert-watcher

go 1.20

require gopkg.in/yaml.v2 v2.4.0
require (
github.com/alecthomas/kong v0.8.1
gopkg.in/yaml.v2 v2.4.0
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/kong v0.8.1 h1:acZdn3m4lLRobeh3Zi2S2EpnXTd1mOL6U7xVml+vfkY=
github.com/alecthomas/kong v0.8.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
Expand Down
2 changes: 1 addition & 1 deletion helm/templates/cron.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ spec:
command:
- /bin/sh
- -c
- /bin/concert-watcher -apiKey $TICKETMASTER_API_KEY -artistFile /config/artists -discordWebhookURL $DISCORD_WEBHOOK_URL -ticketmasterConfig /config/ticketmaster.yaml --diff --diffFile /data/previous-ids
- /bin/concert-watcher scan --api-key $TICKETMASTER_API_KEY --artist-file /config/artists --discord-webhook-url $DISCORD_WEBHOOK_URL --ticketmaster-config /config/ticketmaster.yaml --diff --diff-file /data/previous-ids
env:
- name: "TICKETMASTER_API_KEY"
value: "{{ .Values.ticketmaster.apiKey }}"
Expand Down
76 changes: 76 additions & 0 deletions internal/commands/scan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package commands

import (
"bufio"
"fmt"
"log"
"os"
"sort"

"github.com/RyanConnell/concert-watcher/internal/watcher"
"github.com/RyanConnell/concert-watcher/pkg/ticketmaster"
)

// ScanCmd defines arguments for the "./concert-watcher scan" sub-command.
type ScanCmd struct {
APIKey string `help:"Ticketmaster API Key"`
ArtistFile string `help:"Path to file containing a list of artists to monitor"`
DiscordWebhookURL string `help:"Discord Webhook URL"`
TicketmasterConfig string `help:"Path to file containing ticketmaster search criteria"`
Diff bool `help:"Only notify for events we haven't already seen"`
DiffFile string `default:"previous-ids" help:"Path to a file that stores the list of events we have previously sent notifications for"`
}

func (s *ScanCmd) Run() {
// Ticketmaster will give us an authentication error if we don't have an API key.
if s.APIKey == "" {
log.Fatalf("Unable to run without a Ticketmaster API key. " +
"Please pass one via the --apiKey option")
return
}

// Read artists
artists, err := readLines(s.ArtistFile)
if err != nil {
log.Fatalf("Error reading file: %v", err)
return
}

reader := ticketmaster.NewReader(s.APIKey)
watcher := watcher.NewWatcher(reader, s.TicketmasterConfig, artists,
s.DiscordWebhookURL, s.DiffFile)
events, err := watcher.FindEvents(s.Diff)
if err != nil {
log.Fatalf("Error retrieving events: %v", err)
return
}

// Sort our events by date
sort.Slice(events, func(i, j int) bool {
return events[i].Date() < events[j].Date()
})
fmt.Printf("Found %d matching events\n", len(events))
for _, event := range events {
fmt.Printf("- %s\n", event.String())
}

if err := watcher.Notify(events); err != nil {
log.Fatalf("Error notifying discord: %v", err)
return
}
}

func readLines(fileName string) ([]string, error) {
file, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer file.Close()

scanner := bufio.NewScanner(file)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, nil
}

0 comments on commit 92ca660

Please sign in to comment.