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

Commit e8f0351

Browse files
authored
feat(triggers/sonarr): support the new events (#91)
* refactor: test event as info log * feat(triggers): more sonarr events * refactor(triggers): include event type in logs
1 parent 254d5ef commit e8f0351

9 files changed

Lines changed: 192 additions & 22 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,13 @@ To add your webhook to Sonarr, Radarr or Lidarr, do:
261261
7. Set the URL to Autoscan's URL and add `/triggers/:name` where name is the name set in the trigger's config.
262262
8. Optional: set username and password.
263263

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

266273
Triggers pass the Scans they receive to the processor.

triggers/lidarr/lidarr.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
6666
l.Trace().Interface("event", event).Msg("Received JSON body")
6767

6868
if strings.EqualFold(event.Type, "Test") {
69-
l.Debug().Msg("Received test event")
69+
l.Info().Msg("Received test event")
7070
rw.WriteHeader(http.StatusOK)
7171
return
7272
}
@@ -105,6 +105,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
105105
rw.WriteHeader(http.StatusOK)
106106
l.Info().
107107
Str("path", scans[0].Folder).
108+
Str("event", event.Type).
108109
Msg("Scan moved to processor")
109110
}
110111

triggers/radarr/radarr.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
7070
rlog.Trace().Interface("event", event).Msg("Received JSON body")
7171

7272
if strings.EqualFold(event.Type, "Test") {
73-
rlog.Debug().Msg("Received test event")
73+
rlog.Info().Msg("Received test event")
7474
rw.WriteHeader(http.StatusOK)
7575
return
7676
}
@@ -100,6 +100,7 @@ func (h handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
100100
rw.WriteHeader(http.StatusOK)
101101
rlog.Info().
102102
Str("path", folderPath).
103+
Str("event", event.Type).
103104
Msg("Scan moved to processor")
104105
}
105106

triggers/sonarr/sonarr.go

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ type sonarrEvent struct {
5353
Series struct {
5454
Path string
5555
} `json:"series"`
56+
57+
RenamedFiles []struct {
58+
// use PreviousPath as the Series.Path might have changed.
59+
PreviousPath string
60+
RelativePath string
61+
} `json:"renamedEpisodeFiles"`
5662
}
5763

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

7278
if strings.EqualFold(event.Type, "Test") {
73-
rlog.Debug().Msg("Received test event")
79+
rlog.Info().Msg("Received test event")
7480
rw.WriteHeader(http.StatusOK)
7581
return
7682
}
7783

78-
if !strings.EqualFold(event.Type, "Download") || event.File.RelativePath == "" || event.Series.Path == "" {
79-
rlog.Error().Msg("Required fields are missing")
80-
rw.WriteHeader(http.StatusBadRequest)
81-
return
84+
var paths []string
85+
86+
// a Download event is either an upgrade or a new file.
87+
// the EpisodeFileDelete event shares the same request format as Download.
88+
if strings.EqualFold(event.Type, "Download") || strings.EqualFold(event.Type, "EpisodeFileDelete") {
89+
if event.File.RelativePath == "" || event.Series.Path == "" {
90+
rlog.Error().Msg("Required fields are missing")
91+
return
92+
}
93+
94+
// Use path.Dir to get the directory in which the file is located
95+
folderPath := path.Dir(path.Join(event.Series.Path, event.File.RelativePath))
96+
paths = append(paths, folderPath)
97+
}
98+
99+
// An entire show has been deleted
100+
if strings.EqualFold(event.Type, "SeriesDelete") {
101+
if event.Series.Path == "" {
102+
rlog.Error().Msg("Required fields are missing")
103+
return
104+
}
105+
106+
// Scan the folder of the show
107+
paths = append(paths, event.Series.Path)
108+
}
109+
110+
if strings.EqualFold(event.Type, "Rename") {
111+
if event.Series.Path == "" {
112+
rlog.Error().Msg("Required fields are missing")
113+
return
114+
}
115+
116+
// Keep track of which paths we have already added to paths.
117+
encountered := make(map[string]bool)
118+
119+
for _, renamedFile := range event.RenamedFiles {
120+
previousPath := path.Dir(renamedFile.PreviousPath)
121+
currentPath := path.Dir(path.Join(event.Series.Path, renamedFile.RelativePath))
122+
123+
// if previousPath not in paths, then add it.
124+
if _, ok := encountered[previousPath]; !ok {
125+
encountered[previousPath] = true
126+
paths = append(paths, previousPath)
127+
}
128+
129+
// if currentPath not in paths, then add it.
130+
if _, ok := encountered[currentPath]; !ok {
131+
encountered[currentPath] = true
132+
paths = append(paths, currentPath)
133+
}
134+
}
82135
}
83136

84-
// Rewrite the path based on the provided rewriter.
85-
folderPath := path.Dir(h.rewrite(path.Join(event.Series.Path, event.File.RelativePath)))
137+
var scans []autoscan.Scan
138+
139+
for _, folderPath := range paths {
140+
folderPath := h.rewrite(folderPath)
141+
142+
scan := autoscan.Scan{
143+
Folder: folderPath,
144+
Priority: h.priority,
145+
Time: now(),
146+
}
86147

87-
scan := autoscan.Scan{
88-
Folder: folderPath,
89-
Priority: h.priority,
90-
Time: now(),
148+
scans = append(scans, scan)
91149
}
92150

93-
err = h.callback(scan)
151+
err = h.callback(scans...)
94152
if err != nil {
95-
rlog.Error().Err(err).Msg("Processor could not process scan")
153+
rlog.Error().Err(err).Msg("Processor could not process scans")
96154
rw.WriteHeader(http.StatusInternalServerError)
97155
return
98156
}
99157

158+
for _, scan := range scans {
159+
rlog.Info().
160+
Str("path", scan.Folder).
161+
Str("event", event.Type).
162+
Msg("Scan moved to processor")
163+
}
164+
100165
rw.WriteHeader(http.StatusOK)
101-
rlog.Info().
102-
Str("path", folderPath).
103-
Msg("Scan moved to processor")
104166
}
105167

106168
var now = time.Now

triggers/sonarr/sonarr_test.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestHandler(t *testing.T) {
4545

4646
var testCases = []Test{
4747
{
48-
"Scan has all the correct fields",
48+
"Scan has all the correct fields on Download event",
4949
Given{
5050
Config: standardConfig,
5151
Fixture: "testdata/westworld.json",
@@ -61,6 +61,72 @@ func TestHandler(t *testing.T) {
6161
},
6262
},
6363
},
64+
{
65+
"Scan on EpisodeFileDelete",
66+
Given{
67+
Config: standardConfig,
68+
Fixture: "testdata/episode_delete.json",
69+
},
70+
Expected{
71+
StatusCode: 200,
72+
Scans: []autoscan.Scan{
73+
{
74+
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 2",
75+
Priority: 5,
76+
Time: currentTime,
77+
},
78+
},
79+
},
80+
},
81+
{
82+
"Picks up the Rename event without duplicates",
83+
Given{
84+
Config: standardConfig,
85+
Fixture: "testdata/rename.json",
86+
},
87+
Expected{
88+
StatusCode: 200,
89+
Scans: []autoscan.Scan{
90+
{
91+
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 1",
92+
Priority: 5,
93+
Time: currentTime,
94+
},
95+
{
96+
Folder: "/mnt/unionfs/Media/TV/Westworld [imdb:tt0475784]/Season 1",
97+
Priority: 5,
98+
Time: currentTime,
99+
},
100+
{
101+
Folder: "/mnt/unionfs/Media/TV/Westworld/Season 2",
102+
Priority: 5,
103+
Time: currentTime,
104+
},
105+
{
106+
Folder: "/mnt/unionfs/Media/TV/Westworld [imdb:tt0475784]/Season 2",
107+
Priority: 5,
108+
Time: currentTime,
109+
},
110+
},
111+
},
112+
},
113+
{
114+
"Scans show folder on SeriesDelete event",
115+
Given{
116+
Config: standardConfig,
117+
Fixture: "testdata/series_delete.json",
118+
},
119+
Expected{
120+
StatusCode: 200,
121+
Scans: []autoscan.Scan{
122+
{
123+
Folder: "/mnt/unionfs/Media/TV/Westworld",
124+
Priority: 5,
125+
Time: currentTime,
126+
},
127+
},
128+
},
129+
},
64130
{
65131
"Returns bad request on invalid JSON",
66132
Given{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"eventType": "EpisodeFileDelete",
3+
"episodeFile": {
4+
"relativePath": "Season 2/Westworld.S02E01.mkv"
5+
},
6+
"series": {
7+
"path": "/TV/Westworld"
8+
}
9+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"eventType": "Rename",
3+
"series": {
4+
"path": "/TV/Westworld [imdb:tt0475784]"
5+
},
6+
"renamedEpisodeFiles": [
7+
{
8+
"previousPath": "/TV/Westworld/Season 1/Westworld.S01E01.mkv",
9+
"relativePath": "Season 1/Westworld.S01E01.mkv"
10+
},
11+
{
12+
"previousPath": "/TV/Westworld/Season 1/Westworld.S01E02.mkv",
13+
"relativePath": "Season 1/Westworld.S01E02.mkv"
14+
},
15+
{
16+
"previousPath": "/TV/Westworld/Season 2/Westworld.S01E02.mkv",
17+
"relativePath": "Season 2/Westworld.S02E01.mkv"
18+
}
19+
]
20+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"eventType": "SeriesDelete",
3+
"series": {
4+
"path": "/TV/Westworld"
5+
}
6+
}
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
{
22
"eventType": "Download",
3-
"isUpgrade": false,
43
"episodeFile": {
5-
"relativePath": "Season 1/Westworld.S01E01.The.Original.2160p.TrueHD.Atmos.7.1.HEVC.REMUX.mkv"
4+
"relativePath": "Season 1/Westworld.S01E01.mkv"
65
},
76
"series": {
8-
"tvdbId": 296762,
97
"path": "/TV/Westworld"
108
}
119
}

0 commit comments

Comments
 (0)