more customisation, more QoL improvements
an all-around good time!
This commit is contained in:
parent
2954689784
commit
45db651388
9 changed files with 315 additions and 147 deletions
124
main.go
124
main.go
|
|
@ -6,9 +6,12 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
|
|
@ -20,11 +23,11 @@ import (
|
|||
yt "arimelody.space/live-vod-uploader/youtube"
|
||||
)
|
||||
|
||||
const segmentExtension = "mkv"
|
||||
|
||||
//go:embed res/help.txt
|
||||
var helpText string
|
||||
|
||||
const segmentExtension = "mkv"
|
||||
|
||||
func showHelp() {
|
||||
execSplits := strings.Split(os.Args[0], "/")
|
||||
execName := execSplits[len(execSplits) - 1]
|
||||
|
|
@ -64,7 +67,7 @@ func main() {
|
|||
|
||||
case "-d":
|
||||
fallthrough
|
||||
case "-deleteAfter":
|
||||
case "--deleteAfter":
|
||||
deleteFullVod = true
|
||||
|
||||
case "-f":
|
||||
|
|
@ -89,6 +92,11 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
if cfg == nil {
|
||||
err = config.GenerateConfig(config.CONFIG_FILENAME)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to generate config: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Printf(
|
||||
"New config file created (%s). " +
|
||||
"Please edit this file before running again!",
|
||||
|
|
@ -97,6 +105,13 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
// fetch default tags
|
||||
yt.DefaultTags, err = yt.GetDefaultTags(path.Join("template", "tags.txt"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to fetch default tags: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// initialising directory (--init)
|
||||
if initDirectory {
|
||||
err = initialiseDirectory(directory)
|
||||
|
|
@ -104,7 +119,12 @@ func main() {
|
|||
log.Fatalf("Failed to initialise directory: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Printf("Directory successfully initialised")
|
||||
log.Printf(
|
||||
"Directory successfully initialised. " +
|
||||
"Be sure to update %s before uploading!",
|
||||
scanner.METADATA_FILENAME,
|
||||
)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// read directory metadata
|
||||
|
|
@ -131,6 +151,11 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
// default footage directory
|
||||
if len(metadata.FootageDir) == 0 {
|
||||
metadata.FootageDir = directory
|
||||
}
|
||||
|
||||
// scan for VOD segments
|
||||
vodFiles, err := scanner.ScanSegments(metadata.FootageDir, segmentExtension)
|
||||
if err != nil {
|
||||
|
|
@ -175,13 +200,13 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf(
|
||||
"\nTITLE: %s\nDESCRIPTION: %s",
|
||||
"\nTITLE: %s\nDESCRIPTION: %s\n",
|
||||
title, description,
|
||||
)
|
||||
}
|
||||
|
||||
// concatenate VOD segments into full VOD
|
||||
err = vid.ConcatVideo(video, vodFiles, verbose)
|
||||
video.SizeBytes, err = vid.ConcatVideo(video, vodFiles, verbose)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to concatenate VOD segments: %v", err)
|
||||
os.Exit(1)
|
||||
|
|
@ -189,10 +214,20 @@ func main() {
|
|||
|
||||
// youtube oauth flow
|
||||
ctx := context.Background()
|
||||
token, err := completeOAuth(&ctx, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("OAuth flow failed: %v", err)
|
||||
os.Exit(1)
|
||||
var token *oauth2.Token
|
||||
if cfg.Token != nil {
|
||||
token = cfg.Token
|
||||
} else {
|
||||
token, err = generateOAuthToken(&ctx, cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("OAuth flow failed: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cfg.Token = token
|
||||
err = config.WriteConfig(cfg, config.CONFIG_FILENAME)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to save OAuth token: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// okay actually upload now!
|
||||
|
|
@ -219,7 +254,7 @@ func main() {
|
|||
|
||||
// delete full VOD after upload, if requested
|
||||
if deleteFullVod {
|
||||
err = os.Remove(path.Join(directory, scanner.METADATA_FILENAME))
|
||||
err = os.Remove(video.Filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to delete full VOD: %v", err)
|
||||
}
|
||||
|
|
@ -240,7 +275,7 @@ func initialiseDirectory(directory string) error {
|
|||
|
||||
_, err = os.Stat(path.Join(directory, scanner.METADATA_FILENAME))
|
||||
if err == nil {
|
||||
return fmt.Errorf("directory already initialised: %v", err)
|
||||
return fmt.Errorf("directory already initialised: %s", directory)
|
||||
}
|
||||
|
||||
err = scanner.WriteMetadata(directory, scanner.DefaultMetadata())
|
||||
|
|
@ -248,34 +283,69 @@ func initialiseDirectory(directory string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func completeOAuth(ctx *context.Context, cfg *config.Config) (*oauth2.Token, error) {
|
||||
func generateOAuthToken(ctx *context.Context, cfg *config.Config) (*oauth2.Token, error) {
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: cfg.Google.ClientID,
|
||||
ClientSecret: cfg.Google.ClientSecret,
|
||||
Endpoint: google.Endpoint,
|
||||
Scopes: []string{ youtube.YoutubeScope },
|
||||
RedirectURL: "http://localhost:8090",
|
||||
RedirectURL: cfg.RedirectUri,
|
||||
}
|
||||
verifier := oauth2.GenerateVerifier()
|
||||
|
||||
url := oauth2Config.AuthCodeURL("state", oauth2.AccessTypeOffline, oauth2.S256ChallengeOption(verifier))
|
||||
fmt.Printf("Sign in to YouTube: %s\n", url)
|
||||
var token *oauth2.Token
|
||||
wg := sync.WaitGroup{}
|
||||
var server http.Server
|
||||
server.Addr = cfg.Host
|
||||
server.Handler = http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
if !r.URL.Query().Has("code") {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: tidy up oauth flow with localhost webserver
|
||||
var code string
|
||||
fmt.Print("Enter OAuth2 code: ")
|
||||
if _, err := fmt.Scan(&code); err != nil {
|
||||
return nil, fmt.Errorf("failed to read code: %v", err)
|
||||
}
|
||||
code := r.URL.Query().Get("code")
|
||||
|
||||
token, err := oauth2Config.Exchange(*ctx, code, oauth2.VerifierOption(verifier))
|
||||
if err != nil {
|
||||
log.Fatalf("Could not exchange OAuth2 code: %v", err)
|
||||
os.Exit(1)
|
||||
t, err := oauth2Config.Exchange(*ctx, code, oauth2.VerifierOption(verifier))
|
||||
if err != nil {
|
||||
log.Fatalf("Could not exchange OAuth2 code: %v", err)
|
||||
http.Error( w,
|
||||
fmt.Sprintf("Could not exchange OAuth2 code: %v", err),
|
||||
http.StatusBadRequest,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
token = t
|
||||
http.Error(
|
||||
w,
|
||||
"Authentication successful! You may now close this tab.",
|
||||
http.StatusOK,
|
||||
)
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
server.Close()
|
||||
},
|
||||
)
|
||||
|
||||
url := oauth2Config.AuthCodeURL(
|
||||
"state",
|
||||
oauth2.AccessTypeOffline,
|
||||
oauth2.S256ChallengeOption(verifier),
|
||||
)
|
||||
fmt.Printf("\nSign in to YouTube: %s\n\n", url)
|
||||
|
||||
wg.Add(1)
|
||||
if err := server.ListenAndServe(); err != http.ErrServerClosed {
|
||||
return nil, fmt.Errorf("http: %v", err)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// TODO: save this token; look into token refresh
|
||||
log.Printf("Token expires on %s\n", token.Expiry.Format("02 Jan 2006"))
|
||||
log.Printf("Token expires at: %s\n", token.Expiry.Format(time.DateTime))
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue