From 1850201f68d006427b72dc20a1986710ca484dea Mon Sep 17 00:00:00 2001 From: HeshamTB Date: Mon, 22 Jul 2024 10:02:25 +0300 Subject: [PATCH] feat: accept filename for a list of channels - Accept a filename from cli - Fetch and serve based on id as feed name - Still accept single id as usual Signed-off-by: HeshamTB --- cmd/yttopodcast/main.go | 112 +++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/cmd/yttopodcast/main.go b/cmd/yttopodcast/main.go index c601c01..4589819 100644 --- a/cmd/yttopodcast/main.go +++ b/cmd/yttopodcast/main.go @@ -3,10 +3,13 @@ package main import ( "context" "flag" + "fmt" + "io" "log" "net/http" "os" "os/signal" + "strings" "time" "gitea.hbanafa.com/hesham/yttopodcast/bouncer" @@ -21,6 +24,7 @@ var ( fileServAdd = flag.String("fs-addr", "0.0.0.0:8087", "http file server listen address") interval = flag.Int("interval", 30, "update interval for feed in minutes") chan_id = flag.String("id", "", "YouTube channel ID") + chanlist_file = flag.String("list-file", "", "file with newline seperated channel ids") bounc_url = flag.String("bouncer", "http://localhost:8081/?id=%s", "bouncer url as format string") lang = flag.String("lang", "en", "content language") ) @@ -31,16 +35,50 @@ func main() { flag.Parse() l = *log.Default() - if *chan_id == "" { - l.Println("no channel id provided") + + var ids []string + if *chan_id != "" { + l.Println("adding id arg") + ids = append(ids, *chan_id) + } + + if *chanlist_file != "" { + listids, err := func() ([]string, error) { + f, err := os.Open(*chanlist_file) + if err != nil { + return nil, err + } + + content, err := io.ReadAll(f) + if err != nil { + return nil, err + } + + ids := strings.Split(string(content), "\n") + for i := range ids { + ids[i] = strings.ReplaceAll(strings.Join(strings.Fields(ids[i]), ""), "\r", "") + ids[i] = strings.ReplaceAll(ids[i], "\t", "") + } + + return ids[:len(ids)-1], nil + }() + if err != nil { + l.Println(err.Error()) + os.Exit(1) + } + ids = append(ids, listids...) + } + + if len(ids) == 0 { + l.Println("no channel id or list file provided") os.Exit(1) } - - // cache, err := ytlinkprov.NewCachedLinkProvider(time.Minute * time.Duration(*interval)) - // if err != nil { - // l.Println(err.Error()) - // os.Exit(1) - // } + l.Println("channel count: ", len(ids)) + l.Printf("channels: %v\n", ids) + + l.Println("initial feed generation") + genFeeds(ids) + cache := dylinkprovider.NewDynCacheExpLinkProv(&l) bouncer, err := bouncer.NewBouncerHTTPServer(context.Background(), *listenAddr, cache) @@ -49,14 +87,6 @@ func main() { os.Exit(1) } - // This goro is sleeping until interval or SIGINT - // Another one is running the bouncer - - go func() { - l.Printf("http bouncer server starting on %s\n", bouncer.Addr) - l.Println(bouncer.ListenAndServe()) - }() - os.Mkdir("feeds", 0700) mux := http.NewServeMux() @@ -70,15 +100,17 @@ func main() { } go func() { - l.Printf("http file server starting on %s\n", fileServer.Addr) - l.Println(fileServer.ListenAndServe()) + l.Printf("http bouncer server starting on %s\n", bouncer.Addr) + l.Println(bouncer.ListenAndServe()) + l.Println("http bouncer stopped") + }() + + go func() { + l.Printf("http file server starting on %s\n", fileServer.Addr) + l.Println(fileServer.ListenAndServe()) + l.Println("http file server stopped") }() - err = genFeed() - if err != nil { - l.Println(err.Error()) - os.Exit(1) - } sig := make(chan os.Signal) @@ -88,28 +120,50 @@ func main() { for { select { case s := <-sig: + l.Println("got ", s.String()) fileServer.Shutdown(context.Background()) bouncer.Shutdown(context.Background()) break l + case <-time.NewTicker(time.Minute * time.Duration(*interval)).C: - l.Println("tick") - genFeed() + genFeeds(ids) }} } -func genFeed() error { +func genFeeds(ids []string) { + for _, id := range ids { + l.Printf("generating feed for %s\n", id) + err := genFeed(id) + if err != nil { + l.Printf(err.Error()) + continue + } + } +} - l.Println("generating feed") - file, err := os.Create("./feeds/f.xml") +func genFeed(id string) error { + + tmpFilename := fmt.Sprintf("./feeds/%s.xml.t", id) + finalFilename := fmt.Sprintf("./feeds/%s.xml", id) + + file, err := os.Create(tmpFilename) if err != nil { return err } defer file.Close() + defer func() { + l.Printf("removing tempfile %s\n", tmpFilename) + os.Remove(tmpFilename) + }() - return feed.ConvertYtToRss(file, *chan_id, feed.RSSMetadata{ + err = feed.ConvertYtToRss(file, id, feed.RSSMetadata{ Languge: *lang, BounceURL: *bounc_url, }) + + if err != nil { return err } + + return os.Rename(tmpFilename, finalFilename) }