• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brotherlogic / cdprocessor / 18606773929

17 Oct 2025 11:00PM UTC coverage: 53.659%. First build
18606773929

Pull #6345

github

brotherlogic
Better tracking of missing
Pull Request #6345: Raise bug on missing tracks

6 of 43 new or added lines in 2 files covered. (13.95%)

374 of 697 relevant lines covered (53.66%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.05
/cdprocessorutils.go
1
package main
2

3
import (
4
        "fmt"
5
        "io/ioutil"
6
        "os"
7
        "strconv"
8
        "strings"
9
        "time"
10

11
        "golang.org/x/net/context"
12
        "google.golang.org/grpc/codes"
13
        "google.golang.org/grpc/status"
14

15
        pb "github.com/brotherlogic/cdprocessor/proto"
16
        pbcdp "github.com/brotherlogic/cdprocessor/proto"
17
        pbgd "github.com/brotherlogic/godiscogs/proto"
18
        pbrc "github.com/brotherlogic/recordcollection/proto"
19
        "github.com/prometheus/client_golang/prometheus"
20
        "github.com/prometheus/client_golang/prometheus/promauto"
21
)
22

23
var (
24
        needsRip = promauto.NewGauge(prometheus.GaugeOpts{
25
                Name: "cdprocessor_rips",
26
                Help: "The number of records needing a rip",
27
        })
28

29
        ripped24Hours = promauto.NewGauge(prometheus.GaugeOpts{
30
                Name: "cdprocessor_rips_24",
31
                Help: "The number of records needing a rip",
32
        })
33
)
34

35
func (s *Server) findMissing(ctx context.Context) (*pbcdp.Rip, error) {
1✔
36
        localRip, err := s.GetRipped(ctx, &pbcdp.GetRippedRequest{})
1✔
37
        ripped, err := s.master.GetRipped(ctx, &pbcdp.GetRippedRequest{})
1✔
38
        if err != nil {
2✔
39
                return nil, err
1✔
40
        }
1✔
41

42
        for _, rip := range ripped.GetRipped() {
2✔
43
                found := false
1✔
44
                for _, local := range localRip.GetRipped() {
2✔
45
                        if local.Id == rip.Id {
2✔
46
                                found = true
1✔
47
                        }
1✔
48
                }
49

50
                if !found {
2✔
51
                        return rip, nil
1✔
52
                }
1✔
53
        }
54

55
        return nil, nil
1✔
56
}
57

58
// verifies the status of the ripped cd
59
func (s *Server) verify(ctx context.Context, ID int32, config *pb.Config) error {
1✔
60
        record, err := s.getter.getRecord(ctx, ID)
1✔
61
        if err != nil {
2✔
62
                return err
1✔
63
        }
1✔
64

65
        return s.verifyRecord(ctx, record, config)
1✔
66
}
67

68
func (s *Server) verifyRecord(ctx context.Context, record *pbrc.Record, config *pb.Config) error {
1✔
69

1✔
70
        t := time.Now()
1✔
71
        files, err := ioutil.ReadDir(record.GetMetadata().CdPath)
1✔
72
        count := 0
1✔
73
        trackSet := TrackExtract(record.GetRelease(), record.GetMetadata().GetGoalFolder() == 565206)
1✔
74
        for _, track := range trackSet {
2✔
75
                if track.Format == "CD" || track.Format == "CDr" || track.Format == "File" {
2✔
76
                        count++
1✔
77
                }
1✔
78
        }
79
        s.CtxLog(ctx, fmt.Sprintf("Read dir and built trackset in %v", time.Now().Sub(t)))
1✔
80

1✔
81
        if count == 0 {
1✔
82
                count = len(trackSet)
×
83
        }
×
84

85
        s.CtxLog(ctx, fmt.Sprintf("Processing (%v): %v / %v", record.GetRelease().GetInstanceId(), len(files), count))
1✔
86
        err = s.adjustAlert(ctx, config, record, len(files) != count || err != nil)
1✔
87
        if err != nil {
1✔
88
                return err
×
89
        }
×
90
        time.Sleep(time.Second * 2)
1✔
91
        s.CtxLog(ctx, fmt.Sprintf("Found %v files for %v, expected to see %v", len(files), record.GetRelease().GetId(), count))
1✔
92
        if len(files) != count || err != nil {
2✔
93
                files, err = ioutil.ReadDir(record.GetMetadata().CdPath)
1✔
94
                t = time.Now()
1✔
95
                err = s.buildConfig(ctx)
1✔
96
                if err != nil {
1✔
97
                        s.CtxLog(ctx, fmt.Sprintf("Bad config building: %v", err))
×
98
                }
×
99
                s.CtxLog(ctx, fmt.Sprintf("Built conversion config in %v", time.Now().Sub(t)))
1✔
100
                t = time.Now()
1✔
101
                err = s.convertToMP3(ctx, record.GetRelease().GetId())
1✔
102
                s.CtxLog(ctx, fmt.Sprintf("MP3 (%v) conversion in %v", record.GetRelease().GetId(), time.Now().Sub(t)))
1✔
103
                if err != nil {
2✔
104
                        s.CtxLog(ctx, fmt.Sprintf("Bad ripping: %v", err))
1✔
105
                }
1✔
106
                t = time.Now()
1✔
107
                err = s.convertToFlac(ctx, record.GetRelease().GetId())
1✔
108
                s.CtxLog(ctx, fmt.Sprintf("Flac (%v) conversion in %v", record.GetRelease().GetId(), time.Now().Sub(t)))
1✔
109
                if err != nil {
1✔
110
                        s.CtxLog(ctx, fmt.Sprintf("Bad flaccing: %v", err))
×
111
                }
×
112

113
                if len(files) != count || err != nil {
2✔
114
                        s.makeLinks(ctx, record.GetRelease().GetInstanceId(), true, config)
1✔
115

1✔
116
                        if len(files) > count {
1✔
117
                                fstr := ""
×
118
                                for _, file := range files {
×
119
                                        fstr += file.Name() + " ;"
×
120
                                }
×
121
                                s.CtxLog(ctx, fmt.Sprintf("%v (Expected %v)", fstr, count))
×
122
                        }
123
                        return status.Error(codes.DataLoss, fmt.Sprintf("Error reading %v/%v files for %v: (%v)", len(files), count, record.GetRelease().GetId(), err))
1✔
124
                }
125
        }
126

127
        return nil
×
128
}
129

130
func expand(v string) string {
1✔
131
        if len(v) == 1 {
2✔
132
                return "0" + v
1✔
133
        }
1✔
134
        return v
1✔
135
}
136

137
func computeArtist(rec *pbgd.Release) string {
×
138
        str := ""
×
139
        for _, artist := range rec.GetArtists() {
×
140
                str += fmt.Sprintf("%v, ", artist.Name)
×
141
        }
×
142

143
        return str[:len(str)-2]
×
144
}
145

146
func (s *Server) makeLinks(ctx context.Context, ID int32, force bool, config *pb.Config) error {
1✔
147
        record, err := s.getter.getRecord(ctx, ID)
1✔
148
        if err != nil {
2✔
149
                if status.Convert(err).Code() == codes.OutOfRange {
1✔
150
                        return nil
×
151
                }
×
152
                return err
1✔
153
        }
154

155
        if record.GetMetadata().GetFiledUnder() == pbrc.ReleaseMetadata_FILE_TAPE {
1✔
156
                return nil
×
157
        }
×
158

159
        config.GoalFolder[record.GetRelease().GetId()] = record.GetMetadata().GetGoalFolder()
1✔
160

1✔
161
        // Skip records which aren't here yet
1✔
162
        if record.GetMetadata().GetDateArrived() == 0 && time.Since(time.Unix(record.GetMetadata().GetDateAdded(), 0)) < time.Hour*24*365 {
1✔
163
                s.CtxLog(ctx, "Skipping because it's not arrived yet")
×
164
                return nil
×
165
        }
×
166

167
        // Skip records which aren't in the listening pile
168
        if record.GetRelease().GetFolderId() != 7664293 && record.GetRelease().GetFolderId() != 7651472 && record.GetRelease().GetFolderId() != 812802 {
1✔
169
                s.CtxLog(ctx, "Skipping because it's not in the listening pile")
×
170
                return nil
×
171
        }
×
172

173
        // Skip SOLD_ARCHIVE records
174
        if !force && record.GetMetadata().GetCategory() == pbrc.ReleaseMetadata_SOLD_ARCHIVE {
1✔
175
                s.CtxLog(ctx, "Skipping because it's SOLD_ARCHIVE")
×
176
                return nil
×
177
        }
×
178

179
        // Skip records which aren't release yet
180
        val, err := time.Parse("2006-01-02", record.GetRelease().GetReleased())
1✔
181
        s.CtxLog(ctx, fmt.Sprintf("Got %v, %v", val, err))
1✔
182
        if err == nil && val.After(time.Now()) {
1✔
183
                s.CtxLog(ctx, "Skipping because it's UNRELEASED")
×
184
                return nil
×
185
        }
×
186

187
        // Skip boxed records
188
        if record.GetMetadata().GetBoxState() != pbrc.ReleaseMetadata_BOX_UNKNOWN &&
1✔
189
                record.GetMetadata().GetBoxState() != pbrc.ReleaseMetadata_OUT_OF_BOX {
1✔
190
                return nil
×
191
        }
×
192

193
        //Don't do anythng if we're in limbo folder
194
        if record.GetRelease().GetFolderId() == 3380098 && record.GetMetadata().GetMoveFolder() == 0 {
1✔
195
                return nil
×
196
        }
×
197

198
        if time.Since(time.Unix(config.GetLastProcessTime()[record.GetRelease().GetInstanceId()], 0)) > time.Hour*24*7 {
2✔
199
                if config.GetLastProcessTime()[record.GetRelease().GetInstanceId()] > 0 {
1✔
200
                        s.CtxLog(ctx, fmt.Sprintf("Setting force since %v", time.Since(time.Unix(config.GetLastProcessTime()[record.GetRelease().GetInstanceId()], 0))))
×
201
                        force = true
×
202
                }
×
203
        }
204
        err = s.runLinks(ctx, ID, force, record, config)
1✔
205
        s.CtxLog(ctx, fmt.Sprintf("Error on run links: %v", err))
1✔
206

1✔
207
        if err != nil {
2✔
208
                return err
1✔
209
        }
1✔
210
        config.LastProcessTime[record.GetRelease().GetInstanceId()] = time.Now().Unix()
×
211

×
212
        if record.GetRelease().GetFolderId() != 7664293 {
×
213
                return s.save(ctx, config)
×
214
        }
×
215

216
        if err != nil {
×
217
                return err
×
218
        }
×
219

220
        s.CtxLog(ctx, fmt.Sprintf("Adjust force and saving %v", time.Since(time.Unix(config.GetLastProcessTime()[record.GetRelease().GetInstanceId()], 0))))
×
221

×
222
        return s.save(ctx, config)
×
223
}
224

225
func (s *Server) runLinks(ctx context.Context, ID int32, force bool, record *pbrc.Record, config *pb.Config) error {
1✔
226
        s.CtxLog(ctx, fmt.Sprintf("Running linkes %v -> %v", ID, force))
1✔
227
        // Don't process digital CDs
1✔
228
        if record.GetMetadata().GetGoalFolder() == 268147 ||
1✔
229
                record.GetMetadata().GetGoalFolder() == 1433217 {
1✔
230
                s.CtxLog(ctx, fmt.Sprintf("Not processing digital CD (%v)", ID))
×
231
                return nil
×
232
        }
×
233

234
        match := false
1✔
235
        if record.GetMetadata().GetGoalFolder() != 242018 &&
1✔
236
                record.GetMetadata().GetGoalFolder() != 1782105 &&
1✔
237
                record.GetMetadata().GetGoalFolder() != 288751 &&
1✔
238
                record.GetMetadata().GetGoalFolder() != 2274270 &&
1✔
239
                record.GetMetadata().GetGoalFolder() != 565206 {
2✔
240
                // Not a cd or a bandcamp or cd boxset
1✔
241
                for _, format := range record.GetRelease().GetFormats() {
2✔
242
                        if format.GetName() == "File" || format.GetName() == "CD" || format.GetName() == "CDr" || format.GetName() == "Memory Stick" {
2✔
243
                                s.CtxLog(ctx, fmt.Sprintf("Matched %v on the format: %v", ID, format))
1✔
244
                                match = true
1✔
245
                        }
1✔
246
                }
247
        } else {
×
248
                s.CtxLog(ctx, fmt.Sprintf("Matched %v since it has the right goal folder: %v ( => %v)", ID, record.GetMetadata().GetGoalFolder(), force))
×
249
                match = true
×
250
        }
×
251

252
        // This is not a CD we can process
253
        if !match {
1✔
254
                s.CtxLog(ctx, fmt.Sprintf("Don't think %v is a rippable format", record.GetRelease().GetInstanceId()))
×
255
                return nil
×
256
        }
×
257

258
        if force || len(record.GetMetadata().CdPath) == 0 {
2✔
259
                /*if len(record.GetMetadata().CdPath) == 0 || strings.Contains(record.GetMetadata().CdPath, "mp3") {
1✔
260
                        t := time.Now()
1✔
261
                        s.getter.updateRecord(ctx, record.GetRelease().GetInstanceId(), fmt.Sprintf("%v%v", s.flacdir, record.GetRelease().Id), "")
1✔
262
                        s.CtxLog(ctx, fmt.Sprintf("Updated record in %v", time.Now().Sub(t)))
1✔
263
                }*/
1✔
264
                os.MkdirAll(fmt.Sprintf("%v%v", s.mp3dir, record.GetRelease().Id), os.ModePerm)
1✔
265
                os.MkdirAll(fmt.Sprintf("%v%v", s.flacdir, record.GetRelease().Id), os.ModePerm)
1✔
266

1✔
267
                t := time.Now()
1✔
268
                trackSet := TrackExtract(record.GetRelease(), record.GetMetadata().GetGoalFolder() == 565206)
1✔
269
                s.CtxLog(ctx, fmt.Sprintf("Extracted %v tracks in %v", len(trackSet), time.Now().Sub(t)))
1✔
270
                noTracks := false
1✔
271
                for _, track := range trackSet {
2✔
272
                        if track.Format == "CD" || track.Format == "CDr" || track.Format == "File" {
2✔
273
                                noTracks = true
1✔
274
                        }
1✔
275
                }
276
                for _, track := range trackSet {
2✔
277
                        if track.Format == "CD" || track.Format == "CDr" || track.Format == "File" || !noTracks {
2✔
278
                                err := s.buildLink(ctx, track, record, config)
1✔
279
                                if err != nil {
2✔
280
                                        return err
1✔
281
                                }
1✔
282
                        } else {
×
283
                                s.CtxLog(ctx, fmt.Sprintf("Skipping %v because %v", track.Position, track.Format))
×
284
                        }
×
285
                }
286

287
                return s.getter.updateRecord(ctx, record.GetRelease().GetInstanceId(), fmt.Sprintf("%v%v", s.flacdir, record.GetRelease().Id), "")
×
288
        }
289

290
        return s.verifyRecord(ctx, record, config)
×
291
}
292

293
func prepend(val string) string {
×
294
        if len(val) == 1 {
×
295
                return fmt.Sprintf("0%v", val)
×
296
        } else {
×
297
                return fmt.Sprintf("%v", val)
×
298
        }
×
299
}
300

301
func (s *Server) buildLink(ctx context.Context, track *TrackSet, record *pbrc.Record, config *pb.Config) error {
1✔
302
        s.CtxLog(ctx, fmt.Sprintf("Building links: %v", track))
1✔
303
        // Verify that the track exists
1✔
304
        adder := ""
1✔
305
        if record.GetRelease().FormatQuantity > 1 && record.GetMetadata().GetFiledUnder() != pbrc.ReleaseMetadata_FILE_DIGITAL {
1✔
306
                adder = fmt.Sprintf("_%v", track.Disk)
×
307
        }
×
308

309
        trackPath := fmt.Sprintf("%v%v%v/track%v.cdda.flac", s.dir, record.GetRelease().Id, adder, expand(track.Position))
1✔
310

1✔
311
        if !s.fileExists(trackPath) {
2✔
312
                s.CtxLog(ctx, fmt.Sprintf("Track %v does not exist", trackPath))
1✔
313
                //s.verifyRecord(ctx, record, config)
1✔
314
                err := s.adjustAlert(ctx, config, record, true)
1✔
315
                if err != nil {
1✔
NEW
316
                        return err
×
NEW
317
                }
×
318
                return status.Errorf(codes.DataLoss, "Missing Track: %v (from %+v -> %v+)", trackPath, track, track.tracks[0])
1✔
319
        }
320

321
        if len(record.GetRelease().GetImages()) > 0 {
×
322
                s.ripper.runCommand(ctx, []string{"wget", record.GetRelease().GetImages()[0].GetUri(), "-O", fmt.Sprintf("%v%v%v/cover.jpg", s.dir, record.GetRelease().Id, adder)}, false)
×
323
        }
×
324

325
        title := GetTitle(track)
×
326
        oldmp3 := fmt.Sprintf("%v%v%v/track%v.cdda.mp3", s.dir, record.GetRelease().Id, adder, expand(track.Position))
×
327
        s.ripper.runCommand(ctx, []string{"ln", "-s", fmt.Sprintf("%v%v%v/track%v.cdda.mp3", s.dir, record.GetRelease().Id, adder, expand(track.Position)), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
328
        s.ripper.runCommand(ctx, []string{"mp3info", "-n", fmt.Sprintf("%v", track.Position), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
329
        s.ripper.runCommand(ctx, []string{"mp3info", "-t", fmt.Sprintf("%v", title), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
330
        s.ripper.runCommand(ctx, []string{"mp3info", "-l", fmt.Sprintf("%v", record.GetRelease().Title), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
331
        s.ripper.runCommand(ctx, []string{"mp3info", "-a", computeArtist(record.GetRelease()), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
332

×
333
        s.ripper.runCommand(ctx, []string{"eyeD3", fmt.Sprintf("--text-frame=TPOS:\"%v/%v\"", track.Disk, record.GetRelease().FormatQuantity), fmt.Sprintf("%v%v/track%v-%v.cdda.mp3", s.mp3dir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
334
        s.ripper.runCommand(ctx, []string{"eyeD3", "--to-v2.4", oldmp3}, false)
×
335
        s.ripper.runCommand(ctx, []string{"eyeD3", "--add-image", fmt.Sprintf("%v%v%v/cover.jpg:FRONT_COVER", s.dir, record.GetRelease().Id, adder), oldmp3}, false)
×
336

×
337
        oldfile := fmt.Sprintf("%v%v%v/track%v.cdda.flac", s.dir, record.GetRelease().Id, adder, expand(track.Position))
×
338
        //newfile := fmt.Sprintf("%v%v/%v-%v.cdda.flac", s.flacdir, record.Id, track.Disk, expand(track.Position))
×
339
        s.ripper.runCommand(ctx, []string{"metaflac", "--remove-tag=artist", fmt.Sprintf("--set-tag=artist=%v", computeArtist(record.GetRelease())), oldfile}, true)
×
340
        s.ripper.runCommand(ctx, []string{"metaflac", fmt.Sprintf("--set-tag=tracknumber=%v", track.Position), oldfile}, true)
×
341
        s.ripper.runCommand(ctx, []string{"metaflac", fmt.Sprintf("--set-tag=discnumber=%v", prepend(track.Disk)), oldfile}, true)
×
342
        s.ripper.runCommand(ctx, []string{"metaflac", "--remove-tag=title", fmt.Sprintf("--set-tag=title=%v", title), oldfile}, true)
×
343
        s.ripper.runCommand(ctx, []string{"metaflac", "--remove-tag=album", fmt.Sprintf("--set-tag=album=%v", record.GetRelease().Title), oldfile}, true)
×
344
        if len(record.GetRelease().GetImages()) > 0 {
×
345
                s.ripper.runCommand(ctx, []string{"metaflac", fmt.Sprintf("--import-picture-from=%v%v%v/cover.jpg", s.dir, record.GetRelease().Id, adder), oldfile}, true)
×
346
        }
×
347
        //s.ripper.runCommand(ctx, []string{"metaflac", fmt.Sprintf("--set-tag=album=\"%v\"", record.Title), fmt.Sprintf("%v%v/%v-%v.cdda.flac", s.flacdir, record.Id, track.Disk, expand(track.Position))})
348
        s.ripper.runCommand(ctx, []string{"ln", fmt.Sprintf("%v%v%v/track%v.cdda.flac", s.dir, record.GetRelease().Id, adder, expand(track.Position)), fmt.Sprintf("%v%v/%v-%v.cdda.flac", s.flacdir, record.GetRelease().Id, track.Disk, expand(track.Position))}, false)
×
349

×
350
        return nil
×
351
}
352

353
func (s *Server) convertToMP3(ctx context.Context, id int32) error {
1✔
354
        found := false
1✔
355
        for _, rip := range s.rips {
2✔
356
                for _, t := range rip.Tracks {
2✔
357
                        if rip.Id == id {
1✔
358
                                found = true
×
359

×
360
                                if len(t.WavPath) > 0 && len(t.Mp3Path) == 0 && strings.Contains(t.WavPath, "track") {
×
361
                                        s.CtxLog(ctx, fmt.Sprintf("Missing MP3: %v", s.dir+t.WavPath))
×
362
                                        s.ripCount++
×
363
                                        s.ripper.ripToMp3(ctx, s.dir+t.WavPath, s.dir+t.WavPath[0:len(t.WavPath)-3]+"mp3")
×
364
                                        s.buildConfig(ctx)
×
365
                                        return nil
×
366
                                }
×
367
                        }
368
                }
369
        }
370
        if !found {
2✔
371
                return fmt.Errorf("Unable to locate rip for %v", id)
1✔
372
        }
1✔
373

374
        return nil
×
375
}
376

377
func (s *Server) convertToFlac(ctx context.Context, id int32) error {
1✔
378
        time.Sleep(time.Second * 2)
1✔
379
        found := false
1✔
380
        for _, rip := range s.rips {
2✔
381
                if rip.Id == id {
1✔
382
                        found = true
×
383

×
384
                        for _, t := range rip.Tracks {
×
385
                                if len(t.WavPath) > 0 && len(t.FlacPath) == 0 && strings.Contains(t.WavPath, "track") {
×
386
                                        s.CtxLog(ctx, fmt.Sprintf("Missing FLAC: %v", s.dir+t.WavPath))
×
387
                                        s.flacCount++
×
388
                                        s.ripper.ripToFlac(ctx, s.dir+t.WavPath, s.dir+t.WavPath[0:len(t.WavPath)-3]+"flac")
×
389
                                        s.buildConfig(ctx)
×
390
                                        return nil
×
391
                                }
×
392
                        }
393
                }
394
        }
395

396
        if !found {
2✔
397
                s.CtxLog(ctx, fmt.Sprintf("Did not find any flacs for %v", id))
1✔
398
        }
1✔
399
        return nil
1✔
400
}
401

402
func (s *Server) buildConfig(ctx context.Context) error {
1✔
403
        files, err := s.io.readDir()
1✔
404
        if err != nil {
2✔
405
                return err
1✔
406
        }
1✔
407

408
        rips := []*pbcdp.Rip{}
1✔
409
        for _, f := range files {
2✔
410
                if f.IsDir() && f.Name() != "lost+found" {
2✔
411
                        name := f.Name()
1✔
412
                        id, disk, err := s.io.convert(name)
1✔
413
                        if err != nil {
2✔
414
                                s.CtxLog(ctx, fmt.Sprintf("Unable to convert %v -> %v", name, err))
1✔
415
                                continue
1✔
416
                        }
417

418
                        trackFiles, _ := s.io.readSubdir(f.Name())
1✔
419
                        //s.CtxLog(ctx, fmt.Sprintf("Read subdir in %v", time.Now().Sub(t)))
1✔
420
                        tracks := []*pbcdp.Track{}
1✔
421
                        for _, tf := range trackFiles {
2✔
422
                                if !tf.IsDir() && strings.Contains(tf.Name(), "track") {
2✔
423
                                        trackNumber, _ := strconv.ParseInt(tf.Name()[5:7], 10, 32)
1✔
424

1✔
425
                                        var foundTrack *pbcdp.Track
1✔
426
                                        for _, t := range tracks {
2✔
427
                                                if t.TrackNumber == int32(trackNumber) {
2✔
428
                                                        foundTrack = t
1✔
429
                                                }
1✔
430
                                        }
431
                                        if foundTrack == nil {
2✔
432
                                                foundTrack = &pbcdp.Track{TrackNumber: int32(trackNumber), Disk: disk}
1✔
433
                                                tracks = append(tracks, foundTrack)
1✔
434
                                        }
1✔
435

436
                                        if strings.HasSuffix(tf.Name(), "wav") {
2✔
437
                                                foundTrack.WavPath = f.Name() + "/" + tf.Name()
1✔
438
                                        } else if strings.HasSuffix(tf.Name(), "mp3") {
3✔
439
                                                foundTrack.Mp3Path = f.Name() + "/" + tf.Name()
1✔
440
                                        } else if strings.HasSuffix(tf.Name(), "flac") {
3✔
441
                                                foundTrack.FlacPath = f.Name() + "/" + tf.Name()
1✔
442
                                        }
1✔
443
                                }
444
                        }
445

446
                        rips = append(rips, &pbcdp.Rip{Id: id, Path: f.Name(), Tracks: tracks})
1✔
447
                }
448
        }
449

450
        s.rips = rips
1✔
451
        return nil
1✔
452
}
453

454
func (s *Server) adjustAlert(ctx context.Context, config *pbcdp.Config, r *pbrc.Record, needs bool) error {
1✔
455
        number, alreadySeen := config.GetIssueMapping()[r.GetRelease().GetId()]
1✔
456
        s.CtxLog(ctx, fmt.Sprintf("ALERT %v and %v for %v from %v (%v)", number, alreadySeen, r.GetRelease().GetId(), config.GetIssueMapping(), needs))
1✔
457
        if needs && !alreadySeen {
2✔
458
                issue, err := s.ImmediateIssue(ctx, fmt.Sprintf("CD Rip Need for %v", r.GetRelease().GetTitle()), fmt.Sprintf("https://www.discogs.com/madeup/release/%v", r.GetRelease().GetId()), false, false)
1✔
459
                if err != nil {
1✔
460
                        return err
×
461
                }
×
462
                s.CtxLog(ctx, fmt.Sprintf("Adding issue %v -> %v", r.GetRelease(), issue))
1✔
463
                config.IssueMapping[r.GetRelease().GetId()] = issue.GetNumber()
1✔
464

1✔
465
                return s.save(ctx, config)
1✔
466
        }
467

468
        if alreadySeen && !needs {
1✔
469
                err := s.DeleteIssue(ctx, number)
×
470
                if err != nil && status.Convert(err).Code() != codes.NotFound {
×
471
                        return err
×
472
                }
×
473
                delete(config.IssueMapping, r.GetRelease().GetId())
×
474

×
475
                // Update rip time
×
476
                config.GetLastRipTime()[r.GetRelease().GetId()] = time.Now().Unix()
×
477
                s.updateMetrics(ctx, config)
×
478
                return s.save(ctx, config)
×
479
        }
480

481
        return nil
1✔
482
}
483

484
func (s *Server) adjustExisting(ctx context.Context) error {
1✔
485
        t := time.Now()
1✔
486
        m, _ := s.GetRipped(ctx, &pbcdp.GetRippedRequest{})
1✔
487

1✔
488
        for _, r := range m.Ripped {
2✔
489
                rec, err := s.getter.getRecord(ctx, r.Id)
1✔
490
                if err != nil {
1✔
491
                        e, ok := status.FromError(err)
×
492
                        if !ok || e.Code() == codes.InvalidArgument {
×
493
                                s.RaiseIssue("Nil Record Fail", fmt.Sprintf("Nil record?: %v -> %v", r.Id, err))
×
494
                        }
×
495
                }
496

497
                s.getter.updateRecord(ctx, rec.GetRelease().GetInstanceId(), "", r.Path)
1✔
498
                s.adjust++
1✔
499
                break
1✔
500
        }
501

502
        s.lastRunTime = time.Now().Sub(t)
1✔
503

1✔
504
        return nil
1✔
505
}
506

507
func (s *Server) logMissing(ctx context.Context) error {
×
508
        m, _ := s.GetMissing(context.Background(), &pbcdp.GetMissingRequest{})
×
509

×
510
        needsRip.Set(float64(len(m.Missing)))
×
511
        if len(m.Missing) > 0 {
×
512
                s.RaiseIssue("Rip CD", fmt.Sprintf("%v [%v]", m.Missing[0].GetRelease().Title, m.Missing[0].GetRelease().Id))
×
513
        }
×
514

515
        return nil
×
516
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc