Prototype
This commit is contained in:
parent
6e027de406
commit
44994bd14e
6 changed files with 166 additions and 235 deletions
11
config.toml
11
config.toml
|
@ -1,6 +1,11 @@
|
|||
OutputDir = "out/"
|
||||
Channels = [ "https://www.youtube.com/@BudgetBuildsOfficial", "https://www.youtube.com/@RandomGaminginHD" ]
|
||||
TempDir = "/tmp/"
|
||||
|
||||
[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]"
|
||||
AudioFormat = "bestaudio"
|
||||
NumVideos = 2
|
||||
SizeLimit = 4294967296
|
||||
|
|
33
download.go
33
download.go
|
@ -7,7 +7,7 @@ import (
|
|||
"io"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
//"strconv"
|
||||
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
|
@ -33,7 +33,7 @@ func checkURL(input string) (error) {
|
|||
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"
|
||||
|
||||
if err := checkURL(url); err != nil {
|
||||
|
@ -47,21 +47,23 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
|
|||
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 */
|
||||
{
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
io.Copy(file, videoDLResult)
|
||||
|
@ -72,16 +74,16 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
|
|||
|
||||
/* 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
io.Copy(file, audioDLResult)
|
||||
|
@ -90,13 +92,13 @@ func downloadVideo(url string, videoFormat string, audioFormat string, outDir st
|
|||
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 {
|
||||
log.Warnf("Could not remove file \"%s\"", path+"-vid")
|
||||
if err := os.Remove(MainConfig.TempDir+"/"+video.Info.ID+"-vid"); err != nil {
|
||||
log.Warnf("Could not remove file \"%s\"", MainConfig.TempDir+"/"+video.Info.ID+"-vid")
|
||||
}
|
||||
if err := os.Remove(path+"-audio"); err != nil {
|
||||
log.Warnf("Could not remove file \"%s\"", path+"-audio")
|
||||
if err := os.Remove(MainConfig.TempDir+"/"+video.Info.ID+"-audio"); err != nil {
|
||||
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)
|
||||
*/
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@ import (
|
|||
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)}
|
||||
|
||||
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 silent bool
|
||||
|
|
42
substring.go
Normal file
42
substring.go
Normal 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
|
||||
})
|
||||
|
||||
}
|
113
youtube.go
113
youtube.go
|
@ -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
|
||||
}
|
70
ytva.go
70
ytva.go
|
@ -32,18 +32,23 @@ var Flags _flags
|
|||
|
||||
|
||||
|
||||
type ConfigFile struct {
|
||||
type _config struct {
|
||||
TempDir string
|
||||
Group map[string]GroupConfig
|
||||
}
|
||||
|
||||
type GroupConfig struct {
|
||||
URL []string
|
||||
OutputDir string
|
||||
Channels []string
|
||||
YouTube struct {
|
||||
FileName string
|
||||
CFormat string
|
||||
VideoFormat string
|
||||
AudioFormat string
|
||||
}
|
||||
NumVideos uint
|
||||
SizeLimit float64
|
||||
}
|
||||
|
||||
var MainConfig ConfigFile
|
||||
|
||||
|
||||
var MainConfig _config
|
||||
|
||||
func main() {
|
||||
_ = arg.MustParse(&Flags)
|
||||
|
@ -71,25 +76,19 @@ func main() {
|
|||
|
||||
goutubedl.Path = "yt-dlp"
|
||||
|
||||
if _, err := os.Stat(MainConfig.OutputDir); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.Mkdir(MainConfig.OutputDir, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
for name, group := range MainConfig.Group {
|
||||
log.Info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
|
||||
log.Infof("Started group \"%s\"", name)
|
||||
|
||||
for _, channel := range MainConfig.Channels {
|
||||
log.Info("==========================================================================================================")
|
||||
for _, channel := range group.URL {
|
||||
log.Info("================================================================")
|
||||
log.Infof("Channel URL: \"%s\"", channel)
|
||||
|
||||
optType := goutubedl.TypeFromString["channel"]
|
||||
channel, err := goutubedl.New(context.Background(), channel,
|
||||
goutubedl.Options{
|
||||
Type: optType,
|
||||
PlaylistEnd: 2,
|
||||
PlaylistEnd: group.NumVideos,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -98,20 +97,8 @@ func main() {
|
|||
|
||||
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 {
|
||||
log.Debugf("-----------------------------------------------------")
|
||||
log.Debugf("-------------------------------------")
|
||||
log.Debugf("Title: %s", v.Title)
|
||||
log.Debugf("URL: %s", v.WebpageURL)
|
||||
log.Debugf("Playlist: %s", v.Playlist)
|
||||
|
@ -119,19 +106,28 @@ func main() {
|
|||
log.Debugf("IsLive: %t", v.IsLive)
|
||||
//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 os.IsNotExist(err) {
|
||||
if err := os.Mkdir(dirPath, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
log.Debugf("Directory \"%s\" does not exist, creating.", dirPath)
|
||||
if err := os.MkdirAll(dirPath, 0755); err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Downloading video: %s", v.Title)
|
||||
downloadVideo(v.WebpageURL, MainConfig.YouTube.VideoFormat, MainConfig.YouTube.AudioFormat, dirPath, 2^32)
|
||||
downloadVideo(v.WebpageURL, path, group)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue