Skip to content

Commit 1939b48

Browse files
authored
Merge pull request #586 from Unpackerr/dn2_lidarr_manual_import
Manually import FLAC tracks into Lidarr after they're split.
2 parents 407c550 + 9dedda5 commit 1939b48

4 files changed

Lines changed: 84 additions & 11 deletions

File tree

go.mod

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module github.com/Unpackerr/unpackerr
22

33
go 1.26.0
44

5-
//nolint:gomoddirectives // we need to use our own iso9660 package until we fix the issue with the original package.
5+
// we need to use our own iso9660 package until we fix the issue with the original package.
66
replace github.com/kdomanski/iso9660 => github.com/Unpackerr/iso9660 v0.0.1
77

88
require (
@@ -22,9 +22,9 @@ require (
2222
golift.io/cnfg v0.2.5
2323
golift.io/cnfgfile v0.0.0-20240713024420-a5436d84eb48
2424
golift.io/rotatorr v0.0.0-20260217050959-f6ac6fc7b38e
25-
golift.io/starr v1.3.0
25+
golift.io/starr v1.3.1-0.20260220055600-a1399516cfeb
2626
golift.io/version v0.0.2
27-
golift.io/xtractr v0.3.1-0.20260218060125-b814a941badb
27+
golift.io/xtractr v0.3.1-0.20260219054943-e6f0434c2d7a
2828
gopkg.in/yaml.v3 v3.0.1
2929
)
3030

@@ -84,4 +84,3 @@ require (
8484
golift.io/udf v0.0.1 // indirect
8585
google.golang.org/protobuf v1.36.11 // indirect
8686
)
87-

go.sum

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,22 +242,20 @@ golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0
242242
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
243243
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
244244
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
245-
golift.io/cnfg v0.2.4 h1:AfSueg0p6DTCufZjxRWlMSeSAL2eMJ6lN/ySmvpTl50=
246-
golift.io/cnfg v0.2.4/go.mod h1:iMzXYjvZI7iZphzY75hkFR/VShYeuZznXiQtFsBOSCU=
247245
golift.io/cnfg v0.2.5 h1:NwhQ+REL9BSTiHYU4MKMawCEzvtjmhE8RlNiE7XroqE=
248246
golift.io/cnfg v0.2.5/go.mod h1:iMzXYjvZI7iZphzY75hkFR/VShYeuZznXiQtFsBOSCU=
249247
golift.io/cnfgfile v0.0.0-20240713024420-a5436d84eb48 h1:c7cJWRr0cUnFHKtq072esKzhQHKlFA5YRY/hPzQrdko=
250248
golift.io/cnfgfile v0.0.0-20240713024420-a5436d84eb48/go.mod h1:zHm9o8SkZ6Mm5DfGahsrEJPsogyR0qItP59s5lJ98/I=
251249
golift.io/rotatorr v0.0.0-20260217050959-f6ac6fc7b38e h1:FgfNgbg2EUhFzAWPycsbh1dYiFJNLJFDDkn+E298DFQ=
252250
golift.io/rotatorr v0.0.0-20260217050959-f6ac6fc7b38e/go.mod h1:l/fgYTDxyEw15tRLjAtc13M3is1SXMU4hAIE0tdduAQ=
253-
golift.io/starr v1.3.0 h1:dmIt27th+LWIPWHdiHXvDeG8H1h9TT+PQE1ID3DssFY=
254-
golift.io/starr v1.3.0/go.mod h1:W8A/49qhVfoU0HgZyJla4NKRCM5eUHuhSesc+buPIBU=
251+
golift.io/starr v1.3.1-0.20260220055600-a1399516cfeb h1:sRpFSdVj+mb3/ZG57GVDwEzWZlF0UdhGZqFtPrwgaxs=
252+
golift.io/starr v1.3.1-0.20260220055600-a1399516cfeb/go.mod h1:W8A/49qhVfoU0HgZyJla4NKRCM5eUHuhSesc+buPIBU=
255253
golift.io/udf v0.0.1 h1:kEcJVzqqR+IEWGMuPjuVPT9DzXRDukEgsizKAKn1LF8=
256254
golift.io/udf v0.0.1/go.mod h1:ndK7AlWOh+u+nW9tNsQR95dfHsfASG5Y3dMyzVqmPjw=
257255
golift.io/version v0.0.2 h1:i0gXRuSDHKs4O0sVDUg4+vNIuOxYoXhaxspftu2FRTE=
258256
golift.io/version v0.0.2/go.mod h1:76aHNz8/Pm7CbuxIsDi97jABL5Zui3f2uZxDm4vB6hU=
259-
golift.io/xtractr v0.3.1-0.20260218060125-b814a941badb h1:03V2/jDBm5QJTAFB6NxF0esrOJ85u6Vo0DIzQUk069Q=
260-
golift.io/xtractr v0.3.1-0.20260218060125-b814a941badb/go.mod h1:+eMxkIVQjwJENgn9XCSqmsPGuzWOPvn3Ez5YSRM2Dgw=
257+
golift.io/xtractr v0.3.1-0.20260219054943-e6f0434c2d7a h1:GvHGPVvHxogdT4Jf6v4t85tQ5+VULd0gX4kYHh3dsJ8=
258+
golift.io/xtractr v0.3.1-0.20260219054943-e6f0434c2d7a/go.mod h1:bDBgCgojMc0HncBUMD29MYIaupCq9enUbeAYeB8AuNY=
261259
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
262260
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
263261
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=

pkg/unpackerr/handlers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ func (u *Unpackerr) checkExtractDone(now time.Time) {
215215
// handleXtractrCallback handles callbacks from the xtractr library for starr apps (not folders).
216216
// This takes the provided info and logs it then sends it the queue update method.
217217
func (u *Unpackerr) handleXtractrCallback(resp *xtractr.Response) {
218-
if item := u.Map[resp.X.Name]; resp.Done && item != nil {
218+
item := u.Map[resp.X.Name]
219+
if resp.Done && item != nil {
219220
u.updateMetrics(resp, item.App, item.URL)
220221
} else if item != nil {
221222
item.XProg.Archives = resp.Archives.Count() + resp.Extras.Count()
@@ -235,6 +236,11 @@ func (u *Unpackerr) handleXtractrCallback(resp *xtractr.Response) {
235236
resp.Archives.Count(), resp.Extras.Count(), len(resp.NewFiles), bytefmt.ByteSize(resp.Size))
236237
u.Debugf("Extraction Finished: %d files in path: %s", len(files), files)
237238
u.updateQueueStatus(&newStatus{Name: resp.X.Name, Status: EXTRACTED, Resp: resp}, now, true)
239+
240+
if item != nil && item.App == starr.Lidarr && item.SplitFlac &&
241+
extractionHasFlacFiles(resp.NewFiles) {
242+
go u.importSplitFlacTracks(item, u.lidarrServerByURL(item.URL))
243+
}
238244
}
239245
}
240246

pkg/unpackerr/lidarr.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package unpackerr
22

33
import (
44
"errors"
5+
"strings"
56
"time"
67

78
"golift.io/starr"
@@ -136,3 +137,72 @@ func (u *Unpackerr) haveLidarrQitem(name string) bool {
136137

137138
return false
138139
}
140+
141+
// lidarrServerByURL returns the Lidarr server config that matches the given URL, or nil.
142+
func (u *Unpackerr) lidarrServerByURL(url string) *LidarrConfig {
143+
for _, server := range u.Lidarr {
144+
if server.URL == url {
145+
return server
146+
}
147+
}
148+
149+
return nil
150+
}
151+
152+
// extractionHasFlacFiles returns true if any path in files has a .flac extension.
153+
// Used to only trigger manual import after a FLAC+CUE split, not for e.g. zip-of-mp3s.
154+
func extractionHasFlacFiles(files []string) bool {
155+
for _, p := range files {
156+
if strings.HasSuffix(strings.ToLower(p), ".flac") {
157+
return true
158+
}
159+
}
160+
161+
return false
162+
}
163+
164+
// importSplitFlacTracks runs in a goroutine after a Lidarr FLAC+CUE split extraction completes.
165+
// It asks Lidarr for the manual import list for the extract folder and sends the ManualImport command
166+
// so Lidarr imports the split track files.
167+
func (u *Unpackerr) importSplitFlacTracks(item *Extract, server *LidarrConfig) {
168+
if server == nil {
169+
u.Printf("[Lidarr] No Lidarr server found for manual import, this might be a bug: %s", item.Path)
170+
return
171+
}
172+
173+
downloadID, _ := item.IDs["downloadId"].(string)
174+
artistID, _ := item.IDs["artistId"].(int64)
175+
176+
params := &lidarr.ManualImportParams{
177+
Folder: item.Path,
178+
DownloadID: downloadID,
179+
ArtistID: artistID,
180+
FilterExistingFiles: false,
181+
ReplaceExistingFiles: true,
182+
}
183+
184+
outputs, err := server.ManualImport(params)
185+
if err != nil {
186+
u.Errorf("[Lidarr] Manual import list failed for %s: %v", item.Path, err)
187+
return
188+
}
189+
190+
if len(outputs) == 0 {
191+
u.Printf("[Lidarr] No files returned for manual import (folder: %s); import manually in Lidarr", item.Path)
192+
return
193+
}
194+
195+
cmd := lidarr.ManualImportCommandFromOutputs(outputs, true)
196+
if cmd == nil {
197+
u.Printf("[Lidarr] No importable files for manual import: %s", item.Path)
198+
return
199+
}
200+
201+
_, err = server.SendManualImportCommand(cmd)
202+
if err != nil {
203+
u.Errorf("[Lidarr] Manual import command failed for %s: %v", item.Path, err)
204+
return
205+
}
206+
207+
u.Printf("[Lidarr] Manual import triggered for %d files: %s", len(cmd.Files), item.Path)
208+
}

0 commit comments

Comments
 (0)