Skip to content
This repository has been archived by the owner on Aug 3, 2024. It is now read-only.

Commit

Permalink
feat(triggers/sonarr): support the new events (#91)
Browse files Browse the repository at this point in the history
* refactor: test event as info log

* feat(triggers): more sonarr events

* refactor(triggers): include event type in logs
  • Loading branch information
m-rots authored Feb 22, 2021
1 parent 254d5ef commit e8f0351
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 22 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,13 @@ To add your webhook to Sonarr, Radarr or Lidarr, do:
7. Set the URL to Autoscan's URL and add `/triggers/:name` where name is the name set in the trigger's config.
8. Optional: set username and password.

##### Experimental support for more events

Autoscan also supports the new `On Rename`, `On Series Delete` and `On Episode File Delete` Sonarr events.
We have marked support for these events as experimental as the webhook payload may still change.
In addition, we are not 100% sure whether these three events cover all the possible file system interactions.
So for now, please do keep using Bernard or the Inotify trigger to fetch all scans.

### Processor

Triggers pass the Scans they receive to the processor.
Expand Down
3 changes: 2 additions & 1 deletion triggers/lidarr/lidarr.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
l.Trace().Interface("event", event).Msg("Received JSON body")

if strings.EqualFold(event.Type, "Test") {
l.Debug().Msg("Received test event")
l.Info().Msg("Received test event")
rw.WriteHeader(http.StatusOK)
return
}
Expand Down Expand Up @@ -105,6 +105,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
l.Info().
Str("path", scans[0].Folder).
Str("event", event.Type).
Msg("Scan moved to processor")
}

Expand Down
3 changes: 2 additions & 1 deletion triggers/radarr/radarr.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
rlog.Trace().Interface("event", event).Msg("Received JSON body")

if strings.EqualFold(event.Type, "Test") {
rlog.Debug().Msg("Received test event")
rlog.Info().Msg("Received test event")
rw.WriteHeader(http.StatusOK)
return
}
Expand Down Expand Up @@ -100,6 +100,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
rlog.Info().
Str("path", folderPath).
Str("event", event.Type).
Msg("Scan moved to processor")
}

Expand Down
94 changes: 78 additions & 16 deletions triggers/sonarr/sonarr.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ type sonarrEvent struct {
Series struct {
Path string
} `json:"series"`

RenamedFiles []struct {
// use PreviousPath as the Series.Path might have changed.
PreviousPath string
RelativePath string
} `json:"renamedEpisodeFiles"`
}

func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
Expand All @@ -70,37 +76,93 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
rlog.Trace().Interface("event", event).Msg("Received JSON body")

if strings.EqualFold(event.Type, "Test") {
rlog.Debug().Msg("Received test event")
rlog.Info().Msg("Received test event")
rw.WriteHeader(http.StatusOK)
return
}

if !strings.EqualFold(event.Type, "Download") || event.File.RelativePath == "" || event.Series.Path == "" {
rlog.Error().Msg("Required fields are missing")
rw.WriteHeader(http.StatusBadRequest)
return
var paths []string

// a Download event is either an upgrade or a new file.
// the EpisodeFileDelete event shares the same request format as Download.
if strings.EqualFold(event.Type, "Download") || strings.EqualFold(event.Type, "EpisodeFileDelete") {
if event.File.RelativePath == "" || event.Series.Path == "" {
rlog.Error().Msg("Required fields are missing")
return
}

// Use path.Dir to get the directory in which the file is located
folderPath := path.Dir(path.Join(event.Series.Path, event.File.RelativePath))
paths = append(paths, folderPath)
}

// An entire show has been deleted
if strings.EqualFold(event.Type, "SeriesDelete") {
if event.Series.Path == "" {
rlog.Error().Msg("Required fields are missing")
return
}

// Scan the folder of the show
paths = append(paths, event.Series.Path)
}

if strings.EqualFold(event.Type, "Rename") {
if event.Series.Path == "" {
rlog.Error().Msg("Required fields are missing")
return
}

// Keep track of which paths we have already added to paths.
encountered := make(map[string]bool)

for _, renamedFile := range event.RenamedFiles {
previousPath := path.Dir(renamedFile.PreviousPath)
currentPath := path.Dir(path.Join(event.Series.Path, renamedFile.RelativePath))

// if previousPath not in paths, then add it.
if _, ok := encountered[previousPath]; !ok {
encountered[previousPath] = true
paths = append(paths, previousPath)
}

// if currentPath not in paths, then add it.
if _, ok := encountered[currentPath]; !ok {
encountered[currentPath] = true
paths = append(paths, currentPath)
}
}
}

// Rewrite the path based on the provided rewriter.
folderPath := path.Dir(h.rewrite(path.Join(event.Series.Path, event.File.RelativePath)))
var scans []autoscan.Scan

for _, folderPath := range paths {
folderPath := h.rewrite(folderPath)

scan := autoscan.Scan{
Folder: folderPath,
Priority: h.priority,
Time: now(),
}

scan := autoscan.Scan{
Folder: folderPath,
Priority: h.priority,
Time: now(),
scans = append(scans, scan)
}

err = h.callback(scan)
err = h.callback(scans...)
if err != nil {
rlog.Error().Err(err).Msg("Processor could not process scan")
rlog.Error().Err(err).Msg("Processor could not process scans")
rw.WriteHeader(http.StatusInternalServerError)
return
}

for _, scan := range scans {
rlog.Info().
Str("path", scan.Folder).
Str("event", event.Type).
Msg("Scan moved to processor")
}

rw.WriteHeader(http.StatusOK)
rlog.Info().
Str("path", folderPath).
Msg("Scan moved to processor")
}

var now = time.Now
68 changes: 67 additions & 1 deletion triggers/sonarr/sonarr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestHandler(t *testing.T) {

var testCases = []Test{
{
"Scan has all the correct fields",
"Scan has all the correct fields on Download event",
Given{
Config: standardConfig,
Fixture: "testdata/westworld.json",
Expand All @@ -61,6 +61,72 @@ func TestHandler(t *testing.T) {
},
},
},
{
"Scan on EpisodeFileDelete",
Given{
Config: standardConfig,
Fixture: "testdata/episode_delete.json",
},
Expected{
StatusCode: 200,
Scans: []autoscan.Scan{
{
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 2",
Priority: 5,
Time: currentTime,
},
},
},
},
{
"Picks up the Rename event without duplicates",
Given{
Config: standardConfig,
Fixture: "testdata/rename.json",
},
Expected{
StatusCode: 200,
Scans: []autoscan.Scan{
{
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 1",
Priority: 5,
Time: currentTime,
},
{
Folder: "/mnt/unionfs/Media/TV/Westworld [imdb:tt0475784]/Season 1",
Priority: 5,
Time: currentTime,
},
{
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 2",
Priority: 5,
Time: currentTime,
},
{
Folder: "/mnt/unionfs/Media/TV/Westworld [imdb:tt0475784]/Season 2",
Priority: 5,
Time: currentTime,
},
},
},
},
{
"Scans show folder on SeriesDelete event",
Given{
Config: standardConfig,
Fixture: "testdata/series_delete.json",
},
Expected{
StatusCode: 200,
Scans: []autoscan.Scan{
{
Folder: "/mnt/unionfs/Media/TV/Westworld",
Priority: 5,
Time: currentTime,
},
},
},
},
{
"Returns bad request on invalid JSON",
Given{
Expand Down
9 changes: 9 additions & 0 deletions triggers/sonarr/testdata/episode_delete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"eventType": "EpisodeFileDelete",
"episodeFile": {
"relativePath": "Season 2/Westworld.S02E01.mkv"
},
"series": {
"path": "/TV/Westworld"
}
}
20 changes: 20 additions & 0 deletions triggers/sonarr/testdata/rename.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"eventType": "Rename",
"series": {
"path": "/TV/Westworld [imdb:tt0475784]"
},
"renamedEpisodeFiles": [
{
"previousPath": "/TV/Westworld/Season 1/Westworld.S01E01.mkv",
"relativePath": "Season 1/Westworld.S01E01.mkv"
},
{
"previousPath": "/TV/Westworld/Season 1/Westworld.S01E02.mkv",
"relativePath": "Season 1/Westworld.S01E02.mkv"
},
{
"previousPath": "/TV/Westworld/Season 2/Westworld.S01E02.mkv",
"relativePath": "Season 2/Westworld.S02E01.mkv"
}
]
}
6 changes: 6 additions & 0 deletions triggers/sonarr/testdata/series_delete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"eventType": "SeriesDelete",
"series": {
"path": "/TV/Westworld"
}
}
4 changes: 1 addition & 3 deletions triggers/sonarr/testdata/westworld.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
{
"eventType": "Download",
"isUpgrade": false,
"episodeFile": {
"relativePath": "Season 1/Westworld.S01E01.The.Original.2160p.TrueHD.Atmos.7.1.HEVC.REMUX.mkv"
"relativePath": "Season 1/Westworld.S01E01.mkv"
},
"series": {
"tvdbId": 296762,
"path": "/TV/Westworld"
}
}

0 comments on commit e8f0351

Please sign in to comment.