Prototype

This commit is contained in:
Logan G 2024-12-31 16:59:03 -07:00
parent 6e027de406
commit 44994bd14e
Signed by: logan
GPG key ID: E328528C921E7A7A
6 changed files with 166 additions and 235 deletions

View file

@ -1,6 +1,11 @@
OutputDir = "out/" TempDir = "/tmp/"
Channels = [ "https://www.youtube.com/@BudgetBuildsOfficial", "https://www.youtube.com/@RandomGaminginHD" ]
[YouTube] [Group.PCBuilders]
URL = [ "https://www.youtube.com/@BudgetBuildsOfficial", "https://www.youtube.com/@RandomGaminginHD" ]
OutputDir = "out/%Channel%/%Playlist%/"
FileName = "%Timestamp% - %Title%.mkv"
CFormat = "matroska"
VideoFormat = "bestvideo[height<=720]" VideoFormat = "bestvideo[height<=720]"
AudioFormat = "bestaudio" AudioFormat = "bestaudio"
NumVideos = 2
SizeLimit = 4294967296

View file

@ -7,7 +7,7 @@ import (
"io" "io"
"errors" "errors"
"net/http" "net/http"
"strconv" //"strconv"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
@ -33,7 +33,7 @@ func checkURL(input string) (error) {
return nil return nil
} }
func downloadVideo(url string, videoFormat string, audioFormat string, outDir string, sizeLimit float64) (err error) { func downloadVideo(url string, path string, group GroupConfig) (err error) {
goutubedl.Path = "yt-dlp" goutubedl.Path = "yt-dlp"
if err := checkURL(url); err != nil { if err := checkURL(url); err != nil {
@ -47,21 +47,23 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
return err return err
} }
path := outDir+strconv.Itoa(int(video.Info.Timestamp))+" - "+video.Info.Title if video.Info.IsLive {
log.Info("Video is a live stream. Skipping.")
return nil
}
if ! video.Info.IsLive {
/* VIDEO */ /* VIDEO */
{ {
log.Debugf("Downloading video \"%s\" with format \"%s\"", video.Info.ID, videoFormat) log.Debugf("Downloading video \"%s\" with format \"%s\"", video.Info.ID, group.VideoFormat)
videoDLResult, err := video.Download(context.Background(), videoFormat) videoDLResult, err := video.Download(context.Background(), group.VideoFormat)
if err != nil { if err != nil {
return err return err
} }
defer videoDLResult.Close() defer videoDLResult.Close()
file, err := os.OpenFile(path+"-vid", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) file, err := os.OpenFile(MainConfig.TempDir+"/"+video.Info.ID+"-vid", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer file.Close() defer file.Close()
io.Copy(file, videoDLResult) io.Copy(file, videoDLResult)
@ -72,16 +74,16 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
/* AUDIO */ /* AUDIO */
{ {
log.Debugf("Downloading audio \"%s\" with format \"%s\"", video.Info.ID, audioFormat) log.Debugf("Downloading audio \"%s\" with format \"%s\"", video.Info.ID, group.AudioFormat)
audioDLResult, err := video.Download(context.Background(), audioFormat) audioDLResult, err := video.Download(context.Background(), group.AudioFormat)
if err != nil { if err != nil {
return err return err
} }
defer audioDLResult.Close() defer audioDLResult.Close()
file, err := os.OpenFile(path+"-audio", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) file, err := os.OpenFile(MainConfig.TempDir+"/"+video.Info.ID+"-audio", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer file.Close() defer file.Close()
io.Copy(file, audioDLResult) io.Copy(file, audioDLResult)
@ -90,13 +92,13 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
file.Close() file.Close()
} }
mergeStreams(path+"-vid",path+"-audio",path+".mkv") mergeStreams(MainConfig.TempDir+"/"+video.Info.ID+"-vid",MainConfig.TempDir+"/"+video.Info.ID+"-audio", group.CFormat, path)
if err := os.Remove(path+"-vid"); err != nil { if err := os.Remove(MainConfig.TempDir+"/"+video.Info.ID+"-vid"); err != nil {
log.Warnf("Could not remove file \"%s\"", path+"-vid") log.Warnf("Could not remove file \"%s\"", MainConfig.TempDir+"/"+video.Info.ID+"-vid")
} }
if err := os.Remove(path+"-audio"); err != nil { if err := os.Remove(MainConfig.TempDir+"/"+video.Info.ID+"-audio"); err != nil {
log.Warnf("Could not remove file \"%s\"", path+"-audio") log.Warnf("Could not remove file \"%s\"", MainConfig.TempDir+"/"+video.Info.ID+"-audio")
} }
/* /*
@ -107,7 +109,6 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
os.Rename(path, path+"."+extension) os.Rename(path, path+"."+extension)
*/ */
}
return nil return nil
} }

View file

@ -4,10 +4,10 @@ import (
ffmpeg "github.com/u2takey/ffmpeg-go" ffmpeg "github.com/u2takey/ffmpeg-go"
) )
func mergeStreams(path1 string, path2 string, output string) (err error) { func mergeStreams(path1 string, path2 string, format string, output string) (err error) {
input := []*ffmpeg.Stream{ffmpeg.Input(path1), ffmpeg.Input(path2)} input := []*ffmpeg.Stream{ffmpeg.Input(path1), ffmpeg.Input(path2)}
defaultArgs := ffmpeg.KwArgs{"c:v": "copy", "c:a": "copy", "format": "matroska"} defaultArgs := ffmpeg.KwArgs{"c:v": "copy", "c:a": "copy", "format": format}
var ffmpegLogLevel ffmpeg.KwArgs var ffmpegLogLevel ffmpeg.KwArgs
var silent bool var silent bool

42
substring.go Normal file
View file

@ -0,0 +1,42 @@
package main
import (
"regexp"
"reflect"
"fmt"
//"github.com/charmbracelet/log"
"github.com/wader/goutubedl"
)
func fillPlaceholders(input string, videoInfo goutubedl.Info) (output string) {
re := regexp.MustCompile(`%([^%]+)%`)
return re.ReplaceAllStringFunc(input, func(match string) string {
groups := re.FindStringSubmatch(match)
if len(groups) < 1 {
// No capture group found; return original match
return match
}
key := groups[1] // the captured part
v := reflect.ValueOf(videoInfo)
if v.Kind() == reflect.Struct {
fieldVal := v.FieldByName(key)
if fieldVal.IsValid() && fieldVal.CanInterface() {
// Haha cheating :)
if fieldVal.Kind() == reflect.Float64 {
return fmt.Sprintf("%v", int(fieldVal.Float()))
} else {
return fmt.Sprintf("%v", fieldVal.Interface())
}
}
}
// Value not found; return original match
return match
})
}

View file

@ -1,113 +0,0 @@
package main
import (
"context"
"fmt"
"os"
"io"
"errors"
"net/http"
"strconv"
"github.com/charmbracelet/log"
"github.com/wader/goutubedl"
)
func checkURL(input string) (error) {
request, err := http.NewRequest("GET", input, nil)
if err != nil {
return err
}
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
return err
}
if resp.StatusCode == http.StatusNotFound {
return errors.New(fmt.Sprintf("Video does not exist!"))
}
return nil
}
func downloadVideo(url string, videoFormat string, audioFormat string, outDir string, sizeLimit float64) (err error) {
goutubedl.Path = "yt-dlp"
if err := checkURL(url); err != nil {
return err
}
log.Debugf("URL \"%s\" exists.", url)
video, err := goutubedl.New(context.Background(), url, goutubedl.Options{})
if err != nil {
return err
}
path := outDir+strconv.Itoa(int(video.Info.Timestamp))+" - "+video.Info.Title
if ! video.Info.IsLive {
/* VIDEO */
{
log.Debugf("Downloading video \"%s\" with format \"%s\"", video.Info.ID, videoFormat)
videoDLResult, err := video.Download(context.Background(), videoFormat)
if err != nil {
return err
}
defer videoDLResult.Close()
file, err := os.OpenFile(path+"-vid", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer file.Close()
io.Copy(file, videoDLResult)
videoDLResult.Close()
file.Close()
}
/* AUDIO */
{
log.Debugf("Downloading audio \"%s\" with format \"%s\"", video.Info.ID, audioFormat)
audioDLResult, err := video.Download(context.Background(), audioFormat)
if err != nil {
return err
}
defer audioDLResult.Close()
file, err := os.OpenFile(path+"-audio", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer file.Close()
io.Copy(file, audioDLResult)
audioDLResult.Close()
file.Close()
}
mergeStreams(path+"-vid",path+"-audio",path+".mkv")
if err := os.Remove(path+"-vid"); err != nil {
log.Warnf("Could not remove file \"%s\"", path+"-vid")
}
if err := os.Remove(path+"-audio"); err != nil {
log.Warnf("Could not remove file \"%s\"", path+"-audio")
}
/*
extension, err := getExtension(path)
if err != nil {
return err
}
os.Rename(path, path+"."+extension)
*/
}
return nil
}

74
ytva.go
View file

@ -32,18 +32,23 @@ var Flags _flags
type ConfigFile struct { type _config struct {
OutputDir string TempDir string
Channels []string Group map[string]GroupConfig
YouTube struct {
VideoFormat string
AudioFormat string
}
} }
var MainConfig ConfigFile type GroupConfig struct {
URL []string
OutputDir string
FileName string
CFormat string
VideoFormat string
AudioFormat string
NumVideos uint
SizeLimit float64
}
var MainConfig _config
func main() { func main() {
_ = arg.MustParse(&Flags) _ = arg.MustParse(&Flags)
@ -71,25 +76,19 @@ func main() {
goutubedl.Path = "yt-dlp" goutubedl.Path = "yt-dlp"
if _, err := os.Stat(MainConfig.OutputDir); err != nil { for name, group := range MainConfig.Group {
if os.IsNotExist(err) { log.Info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
if err := os.Mkdir(MainConfig.OutputDir, 0755); err != nil { log.Infof("Started group \"%s\"", name)
log.Fatal(err)
}
} else {
log.Fatal(err)
}
}
for _, channel := range MainConfig.Channels { for _, channel := range group.URL {
log.Info("==========================================================================================================") log.Info("================================================================")
log.Infof("Channel URL: \"%s\"", channel) log.Infof("Channel URL: \"%s\"", channel)
optType := goutubedl.TypeFromString["channel"] optType := goutubedl.TypeFromString["channel"]
channel, err := goutubedl.New(context.Background(), channel, channel, err := goutubedl.New(context.Background(), channel,
goutubedl.Options{ goutubedl.Options{
Type: optType, Type: optType,
PlaylistEnd: 2, PlaylistEnd: group.NumVideos,
}, },
) )
if err != nil { if err != nil {
@ -98,20 +97,8 @@ func main() {
log.Infof("Channel Name: %s", channel.Info.Channel) log.Infof("Channel Name: %s", channel.Info.Channel)
basePath := MainConfig.OutputDir+"/"+channel.Info.Channel+"/"
if _, err := os.Stat(basePath); err != nil {
if os.IsNotExist(err) {
if err := os.Mkdir(basePath, 0755); err != nil {
log.Fatal(err)
}
} else {
log.Fatal(err)
}
}
for _, v := range channel.Info.Entries { for _, v := range channel.Info.Entries {
log.Debugf("-----------------------------------------------------") log.Debugf("-------------------------------------")
log.Debugf("Title: %s", v.Title) log.Debugf("Title: %s", v.Title)
log.Debugf("URL: %s", v.WebpageURL) log.Debugf("URL: %s", v.WebpageURL)
log.Debugf("Playlist: %s", v.Playlist) log.Debugf("Playlist: %s", v.Playlist)
@ -119,19 +106,28 @@ func main() {
log.Debugf("IsLive: %t", v.IsLive) log.Debugf("IsLive: %t", v.IsLive)
//log.Debugf("Description: %s\n", item.Snippet.Description) //log.Debugf("Description: %s\n", item.Snippet.Description)
dirPath := basePath+"/"+v.Playlist+"/" dirPath := fillPlaceholders(group.OutputDir, v)
fileName := fillPlaceholders(group.FileName, v)
path := dirPath+"/"+fileName
log.Debugf("Output: %s", path)
if _, err := os.Stat(dirPath); err != nil { if _, err := os.Stat(dirPath); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
if err := os.Mkdir(dirPath, 0755); err != nil { log.Debugf("Directory \"%s\" does not exist, creating.", dirPath)
log.Fatal(err) if err := os.MkdirAll(dirPath, 0755); err != nil {
log.Error(err)
continue
} }
} else { } else {
log.Fatal(err) log.Error(err)
continue
} }
} }
log.Infof("Downloading video: %s", v.Title) log.Infof("Downloading video: %s", v.Title)
downloadVideo(v.WebpageURL, MainConfig.YouTube.VideoFormat, MainConfig.YouTube.AudioFormat, dirPath, 2^32) downloadVideo(v.WebpageURL, path, group)
}
} }
} }
} }