package main import ( "encoding/base64" "fmt" "io" "net/http" "os" "os/exec" "path/filepath" "strings" ) func removeBOM(input []byte) []byte { if len(input) >= 3 && input[0] == 0xEF && input[1] == 0xBB && input[2] == 0xBF { return input[3:] } return input } func downloadFile(item Item, jobInfo *JobInfo) error { fmt.Println("Downloading:", item.Filename) mpdPath := item.MPD if !isValidURL(item.MPD) { decodedMPD, err := base64.StdEncoding.DecodeString(item.MPD) if err != nil { return fmt.Errorf("error decoding base64 MPD: %v", err) } tempFile, err := os.CreateTemp("", "temp_mpd_*.mpd") if err != nil { return fmt.Errorf("error creating temporary MPD file: %v", err) } defer os.Remove(tempFile.Name()) if _, err := tempFile.Write(decodedMPD); err != nil { return fmt.Errorf("error writing to temporary MPD file: %v", err) } if err := tempFile.Close(); err != nil { return fmt.Errorf("error closing temporary MPD file: %v", err) } mpdPath = tempFile.Name() } else if strings.HasPrefix(item.MPD, "https://pubads.g.doubleclick.net") { resp, err := http.Get(item.MPD) if err != nil { return fmt.Errorf("error downloading MPD: %v", err) } defer resp.Body.Close() mpdContent, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("error reading MPD content: %v", err) } fixedMPDContent, err := fixGoPlay(string(mpdContent)) if err != nil { return fmt.Errorf("error fixing MPD content: %v", err) } tempFile, err := os.CreateTemp("", "fixed_mpd_*.mpd") if err != nil { return fmt.Errorf("error creating temporary MPD file: %v", err) } defer os.Remove(tempFile.Name()) if _, err := tempFile.WriteString(fixedMPDContent); err != nil { return fmt.Errorf("error writing to temporary MPD file: %v", err) } if err := tempFile.Close(); err != nil { return fmt.Errorf("error closing temporary MPD file: %v", err) } mpdPath = tempFile.Name() } command := getDownloadCommand(item, mpdPath) if item.Subtitles != "" { subtitlePaths, err := downloadAndConvertSubtitles(item.Subtitles) if err != nil { fmt.Printf("Error processing subtitles: %v\n", err) } else { for _, path := range subtitlePaths { fmt.Println("Adding subtitle:", path) command += fmt.Sprintf(" --mux-import \"path=%s:lang=nl:name=Nederlands\"", path) } } } cmd := exec.Command("bash", "-c", command) jobsMutex.Lock() jobInfo.Cmd = cmd jobsMutex.Unlock() cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Start() if err != nil { return fmt.Errorf("error starting download command: %v", err) } done := make(chan error) go func() { done <- cmd.Wait() }() select { case <-jobInfo.AbortChan: if cmd.Process != nil { cmd.Process.Kill() } return fmt.Errorf("download aborted") case err := <-done: if jobInfo.Paused { return fmt.Errorf("download paused") } if err != nil { return fmt.Errorf("error executing download command: %v", err) } } fmt.Println("Download completed successfully") return nil } func getDownloadCommand(item Item, mpdPath string) string { metadata := parseMetadata(item.Metadata) keys := getKeys(item.Keys) command := fmt.Sprintf("%s %s", config.N_m3u8DLRE.Path, mpdPath) for _, key := range keys { if key != "" { command += fmt.Sprintf(" --key %s", key) } } command += " --auto-select" sanitizedFilename := sanitizeFilename(item.Filename) filename := fmt.Sprintf("\"%s\"", sanitizedFilename) command += fmt.Sprintf(" --save-name %s", filename) command += fmt.Sprintf(" --mux-after-done format=%s", config.Format) saveDir := config.BaseDir if metadata.Type == "serie" { saveDir = filepath.Join(saveDir, "Series", metadata.Title, metadata.Season) } else { saveDir = filepath.Join(saveDir, "Movies", metadata.Title) } command += fmt.Sprintf(" --save-dir \"%s\"", saveDir) fmt.Println(command) return command }