| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | package convids | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2025-07-02 14:14:04 -05:00
										 |  |  | 	"cmp" | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2024-11-04 15:50:34 -06:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	fp "path/filepath" | 
					
						
							|  |  |  | 	"regexp" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2025-04-21 15:19:40 -05:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-21 15:19:40 -05:00
										 |  |  | 	"codeberg.org/danjones000/ezcache" | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	"gopkg.in/yaml.v3" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewData(path string) (*Data, error) { | 
					
						
							| 
									
										
										
										
											2025-07-02 14:14:04 -05:00
										 |  |  | 	//nolint:gosec // I don't care if this is user input | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	f, err := os.Open(path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ydec := yaml.NewDecoder(f) | 
					
						
							|  |  |  | 	var data Data | 
					
						
							|  |  |  | 	err = ydec.Decode(&data) | 
					
						
							|  |  |  | 	return &data, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ensureExtRe(c *Config) (err error) { | 
					
						
							|  |  |  | 	if c.extRe != nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.extRe, err = regexp.Compile("(" + strings.Join(c.Extensions, "|") + ")$") | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | type ShowWalker func(show *Show, path string) error | 
					
						
							|  |  |  | type GroupPrinter func(name string, group Shows) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | var ErrNoFiles = errors.New("no files processed") | 
					
						
							|  |  |  | var ErrSkipped = errors.New("skipped") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | type processInput struct { | 
					
						
							|  |  |  | 	file   os.DirEntry | 
					
						
							|  |  |  | 	source string | 
					
						
							|  |  |  | 	show   *Show | 
					
						
							|  |  |  | 	extRe  *regexp.Regexp | 
					
						
							|  |  |  | 	skips  []string | 
					
						
							|  |  |  | 	walk   ShowWalker | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func processFile(input processInput) (processed bool, processError, cbError error) { | 
					
						
							|  |  |  | 	file := input.file | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	if file.IsDir() { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | 	if !input.extRe.MatchString(file.Name()) { | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | 	show := input.show | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	var found bool | 
					
						
							|  |  |  | 	found, processError = show.Match(file.Name()) | 
					
						
							|  |  |  | 	if processError != nil || !found { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | 	path := fp.Join(input.source, file.Name()) | 
					
						
							|  |  |  | 	for _, ext := range input.skips { | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 		if !strings.HasPrefix(ext, ".") { | 
					
						
							|  |  |  | 			ext = "." + ext | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		skipper := path + ext | 
					
						
							|  |  |  | 		_, statErr := os.Stat(skipper) | 
					
						
							|  |  |  | 		if !errors.Is(statErr, os.ErrNotExist) { | 
					
						
							|  |  |  | 			return processed, ErrSkipped, cbError | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | 	cbError = input.walk(show, path) | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	if cbError == nil { | 
					
						
							|  |  |  | 		processed = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 14:27:19 -05:00
										 |  |  | func processSource(allFiles ezcache.Cache[string, []os.DirEntry], d *Data, s *Show, source string, stopOnError bool, cb ShowWalker) (count int, err error) { | 
					
						
							|  |  |  | 	files, filesErr := allFiles.Get(source) | 
					
						
							|  |  |  | 	if filesErr != nil { | 
					
						
							|  |  |  | 		return 0, filesErr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, file := range files { | 
					
						
							|  |  |  | 		pIn := processInput{file, source, s, d.Config.extRe, d.Config.Skip, cb} | 
					
						
							|  |  |  | 		processed, processErr, cbErr := processFile(pIn) | 
					
						
							|  |  |  | 		if processErr != nil { | 
					
						
							|  |  |  | 			return 0, processErr | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if cbErr != nil && stopOnError { | 
					
						
							|  |  |  | 			return 0, cbErr | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if errors.Is(processErr, ErrSkipped) || (!processed && processErr == nil && cbErr == nil) { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if cbErr == nil && processed { | 
					
						
							|  |  |  | 			count++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if cbErr != nil { | 
					
						
							|  |  |  | 			err = cbErr | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | func WalkFiles(d *Data, stopOnError bool, gp GroupPrinter, cb ShowWalker) (err error) { | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	err = ensureExtRe(d.Config) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 	if cb == nil { | 
					
						
							|  |  |  | 		cb = DryRun(os.Stdout) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	count := 0 | 
					
						
							| 
									
										
										
										
											2025-04-21 15:19:40 -05:00
										 |  |  | 	allFiles, cacheErr := ezcache.New(os.ReadDir, 5*time.Minute) | 
					
						
							|  |  |  | 	if cacheErr != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 	for s := range d.AllShows(gp) { | 
					
						
							| 
									
										
										
										
											2024-11-16 23:38:44 -06:00
										 |  |  | 		if len(s.Sources) == 0 { | 
					
						
							|  |  |  | 			s.Sources = []string{d.Config.Source} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, source := range s.Sources { | 
					
						
							| 
									
										
										
										
											2025-04-24 14:27:19 -05:00
										 |  |  | 			var c int | 
					
						
							|  |  |  | 			c, err = processSource(allFiles, d, s, source, stopOnError, cb) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				break | 
					
						
							| 
									
										
										
										
											2024-11-04 15:50:34 -06:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-04-24 14:27:19 -05:00
										 |  |  | 			count += c | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	if err == nil && count < 1 { | 
					
						
							|  |  |  | 		fmt.Println("Found nothing") | 
					
						
							|  |  |  | 		return ErrNoFiles | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2024-10-23 21:24:10 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | func DryRun(out io.Writer) ShowWalker { | 
					
						
							|  |  |  | 	return func(s *Show, path string) error { | 
					
						
							| 
									
										
										
										
											2025-07-02 14:14:04 -05:00
										 |  |  | 		_, err := fmt.Fprintf(out, "Saving %s to %s\n", path, s.Folder) | 
					
						
							|  |  |  | 		return cmp.Or(err, ErrSkipped) | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func GetShow(ctx context.Context) ShowWalker { | 
					
						
							| 
									
										
										
										
											2024-12-04 11:48:05 -06:00
										 |  |  | 	return GetShowWithIO(ctx, os.Stdin, os.Stdout, os.Stderr) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 14:27:19 -05:00
										 |  |  | func GetShowWithIO(ctx context.Context, stdin io.Reader, stdout, stderr io.Writer) ShowWalker { | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 	return func(s *Show, path string) error { | 
					
						
							| 
									
										
										
										
											2025-04-24 14:27:19 -05:00
										 |  |  | 		//nolint:gosec // I don't care if this is using user input | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 		cmd := exec.CommandContext(ctx, "get-shows", s.Folder, path) | 
					
						
							| 
									
										
										
										
											2024-12-04 11:48:05 -06:00
										 |  |  | 		cmd.Stdin = stdin | 
					
						
							|  |  |  | 		cmd.Stdout = stdout | 
					
						
							|  |  |  | 		cmd.Stderr = stderr | 
					
						
							| 
									
										
										
										
											2024-11-07 05:56:06 -06:00
										 |  |  | 		return cmd.Run() | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-12-04 11:48:05 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func PrintGroupName(out io.Writer) GroupPrinter { | 
					
						
							|  |  |  | 	return func(name string, group Shows) { | 
					
						
							| 
									
										
										
										
											2025-07-02 14:14:04 -05:00
										 |  |  | 		_, _ = fmt.Fprintf(out, "Checking %s shows\n\n", name) | 
					
						
							| 
									
										
										
										
											2024-11-04 15:20:09 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |