Download video to sync to local cache
This commit is contained in:
parent
e554bbfe18
commit
b9bf2f6e73
1 changed files with 203 additions and 2 deletions
205
local/local.go
205
local/local.go
|
@ -1,22 +1,223 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/lbryio/ytsync/v5/downloader/ytdl"
|
||||
|
||||
"github.com/lbryio/lbry.go/v2/extras/jsonrpc"
|
||||
)
|
||||
|
||||
type SyncContext struct {
|
||||
TempDir string
|
||||
LbrynetAddr string
|
||||
}
|
||||
|
||||
func (c *SyncContext) Validate() error {
|
||||
if c.TempDir == "" {
|
||||
return errors.New("No TempDir provided")
|
||||
}
|
||||
if c.LbrynetAddr == "" {
|
||||
return errors.New("No Lbrynet address provided")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var syncContext SyncContext
|
||||
|
||||
func AddCommand(rootCmd *cobra.Command) {
|
||||
cmd := &cobra.Command{
|
||||
Use: "local",
|
||||
Short: "run a personal ytsync",
|
||||
Run: localCmd,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
//cmd.Flags().StringVar(&cache, "cache", "", "path to cache")
|
||||
cmd.Flags().StringVar(&syncContext.TempDir, "temp-dir", getEnvDefault("TEMP_DIR", ""), "directory to use for temporary files")
|
||||
cmd.Flags().StringVar(&syncContext.LbrynetAddr, "lbrynet-address", getEnvDefault("LBRYNET_ADDRESS", ""), "JSONRPC address of the local LBRYNet daemon")
|
||||
rootCmd.AddCommand(cmd)
|
||||
}
|
||||
|
||||
func getEnvDefault(key, defaultValue string) string {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func localCmd(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("local")
|
||||
err := syncContext.Validate()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(syncContext.LbrynetAddr)
|
||||
|
||||
videoID := args[0]
|
||||
fmt.Println(videoID)
|
||||
|
||||
lbrynet := jsonrpc.NewClient(syncContext.LbrynetAddr)
|
||||
lbrynet.SetRPCTimeout(5 * time.Minute)
|
||||
|
||||
status, err := lbrynet.Status()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(status.IsRunning)
|
||||
fmt.Println(status.Wallet.Connected)
|
||||
|
||||
videoBasePath := path.Join(syncContext.TempDir, videoID)
|
||||
|
||||
_, videoMetadataPath, err := getVideoMetadata(videoBasePath, videoID)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting video metadata: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = downloadVideo(videoBasePath, videoMetadataPath)
|
||||
if err != nil {
|
||||
log.Errorf("Error downloading video: %v", err)
|
||||
}
|
||||
|
||||
log.Info("Done")
|
||||
}
|
||||
|
||||
func getVideoMetadata(basePath, videoID string) (*ytdl.YtdlVideo, string, error) {
|
||||
metadataPath := basePath + ".info.json"
|
||||
|
||||
_, err := os.Stat(metadataPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
log.Errorf("Error determining if video metadata already exists: %v", err)
|
||||
return nil, "", err
|
||||
} else if err == nil {
|
||||
log.Debugf("Video metadata file %s already exists. Attempting to load existing file.", metadataPath)
|
||||
videoMetadata, err := loadVideoMetadata(metadataPath)
|
||||
if err != nil {
|
||||
log.Debugf("Error loading pre-existing video metadata: %v. Deleting file and attempting re-download.", err)
|
||||
} else {
|
||||
return videoMetadata, metadataPath, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := downloadVideoMetadata(basePath, videoID); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
videoMetadata, err := loadVideoMetadata(metadataPath)
|
||||
return videoMetadata, metadataPath, err
|
||||
}
|
||||
|
||||
func loadVideoMetadata(path string) (*ytdl.YtdlVideo, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
metadataBytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var videoMetadata *ytdl.YtdlVideo
|
||||
err = json.Unmarshal(metadataBytes, &videoMetadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return videoMetadata, nil
|
||||
}
|
||||
|
||||
func downloadVideoMetadata(basePath, videoID string) error {
|
||||
ytdlArgs := []string{
|
||||
"--skip-download",
|
||||
"--write-info-json",
|
||||
"--force-overwrites",
|
||||
fmt.Sprintf("https://www.youtube.com/watch?v=%s", videoID),
|
||||
"--cookies",
|
||||
"cookies.txt",
|
||||
"-o",
|
||||
basePath,
|
||||
}
|
||||
ytdlCmd := exec.Command("yt-dlp", ytdlArgs...)
|
||||
output, err := runCmd(ytdlCmd)
|
||||
log.Debug(output)
|
||||
return err
|
||||
}
|
||||
|
||||
func downloadVideo(basePath, metadataPath string) error {
|
||||
ytdlArgs := []string{
|
||||
"--no-progress",
|
||||
"-o",
|
||||
basePath,
|
||||
"--merge-output-format",
|
||||
"mp4",
|
||||
"--postprocessor-args",
|
||||
"ffmpeg:-movflags faststart",
|
||||
"--abort-on-unavailable-fragment",
|
||||
"--fragment-retries",
|
||||
"1",
|
||||
"--cookies",
|
||||
"cookies.txt",
|
||||
"--extractor-args",
|
||||
"youtube:player_client=android",
|
||||
"--load-info-json",
|
||||
metadataPath,
|
||||
"-fbestvideo[ext=mp4][vcodec!*=av01][height<=720]+bestaudio[ext!=webm][format_id!=258][format_id!=251][format_id!=256][format_id!=327]",
|
||||
}
|
||||
|
||||
ytdlCmd := exec.Command("yt-dlp", ytdlArgs...)
|
||||
output, err := runCmd(ytdlCmd)
|
||||
log.Debug(output)
|
||||
return err
|
||||
}
|
||||
|
||||
func runCmd(cmd *exec.Cmd) ([]string, error) {
|
||||
log.Infof("running cmd: %s", strings.Join(cmd.Args, " "))
|
||||
var err error
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outLog, err := ioutil.ReadAll(stdout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
errorLog, err := ioutil.ReadAll(stderr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- cmd.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
log.Error(string(errorLog))
|
||||
return nil, err
|
||||
}
|
||||
return strings.Split(strings.Replace(string(outLog), "\r\n", "\n", -1), "\n"), nil
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue