From ae765fdf64ab93c403e40e31955cd5287dd47e93 Mon Sep 17 00:00:00 2001 From: Sebastiaan de Schaetzen Date: Mon, 10 Mar 2025 06:45:58 +0100 Subject: [PATCH] Finish migration to mysqlite --- downloader.go | 224 +++++++++++++++++++++++++------------------------- util.go | 7 ++ 2 files changed, 121 insertions(+), 110 deletions(-) create mode 100644 util.go diff --git a/downloader.go b/downloader.go index 9b1933a..bb8e518 100644 --- a/downloader.go +++ b/downloader.go @@ -16,7 +16,7 @@ import ( "time" ) -func DownloadAllVideos(db *mysqlite.Db) error { +func DownloadAllVideos(db *mysqlite.Db) (rerr error) { // Ensure no partial videos exist tempDir := os.Getenv("VIVAPLUS_DOWNLOAD") if tempDir == "" { @@ -43,116 +43,120 @@ func DownloadAllVideos(db *mysqlite.Db) error { log.Printf("Starting downloads...") for { - // Fetch the next record from the database - var id, episode int - var href, cast, title, description, uploadDateStr, thumbnailUrl string - err = db.Query("select id, url, `cast`, title, description, upload_date, thumbnail, episode from videos where state = 'pending' and episode is not null order by year, episode limit 1"). - ScanSingle(&id, &href, &cast, &title, &description, &uploadDateStr, &thumbnailUrl, &episode) - if errors.Is(err, sql.ErrNoRows) { - log.Printf("No videos found for downloading") - return nil - } + err = downloadVideo(db, downloadDir, tempDir) if err != nil { - return fmt.Errorf("error fetching record: %w", err) + return err } - uploadDate, err := time.Parse(time.DateOnly, uploadDateStr) - if err != nil { - return fmt.Errorf("error parsing upload date '%s': %w", uploadDateStr, err) - } - - // Download the actual video - baseFileName := fmt.Sprintf("/S%dE%03d", uploadDate.Year(), episode) - log.Printf("Downloading %s", href) - cmd := exec.Command("yt-dlp", cast, "-o", filepath.Join(tempDir, baseFileName+".%(ext)s")) - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stdout - err = cmd.Run() - if err != nil { - return fmt.Errorf("error downloading video: %w", err) - } - - // Move it into the destination directory - destinationDir := filepath.Join(downloadDir, fmt.Sprintf("Season %d", uploadDate.Year())) - err = os.MkdirAll(destinationDir, 0750) - if err != nil { - return fmt.Errorf("error creating target directory: %w", err) - } - files, err := os.ReadDir(tempDir) - if err != nil { - return fmt.Errorf("error retrieving downloaded files: %w", err) - } - - for _, file := range files { - srcPath := filepath.Join(tempDir, file.Name()) - destPath := filepath.Join(destinationDir, file.Name()) - log.Printf("Moving %s to %s", srcPath, destPath) - err = os.Rename(srcPath, destPath) - if err != nil { - return fmt.Errorf("error moving file: %w", err) - } - } - - // Write XML sidecar - nfo := NFO{} - nfo.Plot = description - nfo.Title = title - nfo.Year = uploadDate.Year() - nfo.Aired = uploadDate.Format(time.DateOnly) - nfoData, err := xml.MarshalIndent(nfo, "", " ") - if err != nil { - return fmt.Errorf("error marshalling NFO data: %w", err) - } - nfoString := xml.Header + string(nfoData) - nfoFile, err := os.Create(filepath.Join(destinationDir, baseFileName+".nfo")) - defer nfoFile.Close() - _, err = nfoFile.WriteString(nfoString) - if err != nil { - return fmt.Errorf("error writing NFO file: %w", err) - } - - // Write thumbnail - parsedThumbnailUrl, err := url.Parse(thumbnailUrl) - if err != nil { - return fmt.Errorf("error parsing thumbnail url: %w", err) - } - thumbnailExt := filepath.Ext(parsedThumbnailUrl.Path) - thumbnailFile, err := os.Create(filepath.Join(destinationDir, baseFileName+"-thumb"+thumbnailExt)) - if err != nil { - return fmt.Errorf("error creating thumbnail: %w", err) - } - defer thumbnailFile.Close() - thumbnailResp, err := http.Get(thumbnailUrl) - if err != nil { - return fmt.Errorf("error fetching thumbnail: %w", err) - } - defer thumbnailResp.Body.Close() - _, err = io.Copy(thumbnailFile, thumbnailResp.Body) - if err != nil { - return fmt.Errorf("error writing thumbnail: %w", err) - } - - // Set the database state to done - tx, err := db.Begin() - if err != nil { - return fmt.Errorf("error starting transaction: %w", err) - } - defer tx.Rollback() - result, err := tx.Exec("update videos set state = 'done' where id = ?", id) - if err != nil { - return fmt.Errorf("error updating database: %w", err) - } - count, err := result.RowsAffected() - if err != nil { - return fmt.Errorf("error getting number of rows affected: %d", err) - } - if count != 1 { - return fmt.Errorf("unexpected number of rows changed (expected exactly 1): %d", count) - } - err = tx.Commit() - if err != nil { - return fmt.Errorf("error commiting transaction: %w", err) - } - - log.Printf("Finished downloading file") } } + +func downloadVideo(db *mysqlite.Db, downloadDir string, tempDir string) (rerr error) { + // Fetch the next record from the database + var id, episode int + var href, cast, title, description, uploadDateStr, thumbnailUrl string + err := db.Query("select id, url, `cast`, title, description, upload_date, thumbnail, episode from videos where state = 'pending' and episode is not null order by year, episode limit 1"). + ScanSingle(&id, &href, &cast, &title, &description, &uploadDateStr, &thumbnailUrl, &episode) + if errors.Is(err, sql.ErrNoRows) { + log.Printf("No videos found for downloading") + return nil + } + if err != nil { + return fmt.Errorf("error fetching record: %w", err) + } + uploadDate, err := time.Parse(time.DateOnly, uploadDateStr) + if err != nil { + return fmt.Errorf("error parsing upload date '%s': %w", uploadDateStr, err) + } + + // Download the actual video + baseFileName := fmt.Sprintf("/S%dE%03d", uploadDate.Year(), episode) + log.Printf("Downloading %s", href) + cmd := exec.Command("yt-dlp", cast, "-o", filepath.Join(tempDir, baseFileName+".%(ext)s")) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + err = cmd.Run() + if err != nil { + return fmt.Errorf("error downloading video: %w", err) + } + + // Move it into the destination directory + destinationDir := filepath.Join(downloadDir, fmt.Sprintf("Season %d", uploadDate.Year())) + err = os.MkdirAll(destinationDir, 0750) + if err != nil { + return fmt.Errorf("error creating target directory: %w", err) + } + files, err := os.ReadDir(tempDir) + if err != nil { + return fmt.Errorf("error retrieving downloaded files: %w", err) + } + + for _, file := range files { + srcPath := filepath.Join(tempDir, file.Name()) + destPath := filepath.Join(destinationDir, file.Name()) + log.Printf("Moving %s to %s", srcPath, destPath) + err = os.Rename(srcPath, destPath) + if err != nil { + return fmt.Errorf("error moving file: %w", err) + } + } + + // Write XML sidecar + nfo := NFO{} + nfo.Plot = description + nfo.Title = title + nfo.Year = uploadDate.Year() + nfo.Aired = uploadDate.Format(time.DateOnly) + nfoData, err := xml.MarshalIndent(nfo, "", " ") + if err != nil { + return fmt.Errorf("error marshalling NFO data: %w", err) + } + nfoString := xml.Header + string(nfoData) + nfoFile, err := os.Create(filepath.Join(destinationDir, baseFileName+".nfo")) + if err != nil { + return fmt.Errorf("error creating NFO file: %w", err) + } + defer forwardError(nfoFile.Close(), &rerr) + _, err = nfoFile.WriteString(nfoString) + if err != nil { + return fmt.Errorf("error writing NFO file: %w", err) + } + + // Write thumbnail + parsedThumbnailUrl, err := url.Parse(thumbnailUrl) + if err != nil { + return fmt.Errorf("error parsing thumbnail url: %w", err) + } + thumbnailExt := filepath.Ext(parsedThumbnailUrl.Path) + thumbnailFile, err := os.Create(filepath.Join(destinationDir, baseFileName+"-thumb"+thumbnailExt)) + if err != nil { + return fmt.Errorf("error creating thumbnail: %w", err) + } + defer forwardError(thumbnailFile.Close(), &rerr) + thumbnailResp, err := http.Get(thumbnailUrl) + if err != nil { + return fmt.Errorf("error fetching thumbnail: %w", err) + } + defer forwardError(thumbnailResp.Body.Close(), &rerr) + _, err = io.Copy(thumbnailFile, thumbnailResp.Body) + if err != nil { + return fmt.Errorf("error writing thumbnail: %w", err) + } + + // Set the database state to done + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %w", err) + } + defer forwardError(tx.Rollback(), &rerr) + err = tx.Query("update videos set state = 'done' where id = ?").Bind(id).Exec() + if err != nil { + return fmt.Errorf("error updating database: %w", err) + } + err = tx.Commit() + if err != nil { + return fmt.Errorf("error commiting transaction: %w", err) + } + + log.Printf("Finished downloading file") + return nil +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..779867b --- /dev/null +++ b/util.go @@ -0,0 +1,7 @@ +package main + +func forwardError(err error, to *error) { + if err != nil { + *to = err + } +}