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 <hishaminv@gmail.com>
This commit is contained in:
HeshamTB 2024-07-22 10:02:25 +03:00
parent bfec09e5e0
commit 1850201f68
Signed by: Hesham
GPG Key ID: 74876157D199B09E

View File

@ -3,10 +3,13 @@ package main
import ( import (
"context" "context"
"flag" "flag"
"fmt"
"io"
"log" "log"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"strings"
"time" "time"
"gitea.hbanafa.com/hesham/yttopodcast/bouncer" "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") 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") interval = flag.Int("interval", 30, "update interval for feed in minutes")
chan_id = flag.String("id", "", "YouTube channel ID") 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") bounc_url = flag.String("bouncer", "http://localhost:8081/?id=%s", "bouncer url as format string")
lang = flag.String("lang", "en", "content language") lang = flag.String("lang", "en", "content language")
) )
@ -31,16 +35,50 @@ func main() {
flag.Parse() flag.Parse()
l = *log.Default() 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) os.Exit(1)
} }
l.Println("channel count: ", len(ids))
// cache, err := ytlinkprov.NewCachedLinkProvider(time.Minute * time.Duration(*interval)) l.Printf("channels: %v\n", ids)
// if err != nil {
// l.Println(err.Error()) l.Println("initial feed generation")
// os.Exit(1) genFeeds(ids)
// }
cache := dylinkprovider.NewDynCacheExpLinkProv(&l) cache := dylinkprovider.NewDynCacheExpLinkProv(&l)
bouncer, err := bouncer.NewBouncerHTTPServer(context.Background(), *listenAddr, cache) bouncer, err := bouncer.NewBouncerHTTPServer(context.Background(), *listenAddr, cache)
@ -49,14 +87,6 @@ func main() {
os.Exit(1) 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) os.Mkdir("feeds", 0700)
mux := http.NewServeMux() mux := http.NewServeMux()
@ -70,15 +100,17 @@ func main() {
} }
go func() { go func() {
l.Printf("http file server starting on %s\n", fileServer.Addr) l.Printf("http bouncer server starting on %s\n", bouncer.Addr)
l.Println(fileServer.ListenAndServe()) 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) sig := make(chan os.Signal)
@ -88,28 +120,50 @@ func main() {
for { for {
select { select {
case s := <-sig: case s := <-sig:
l.Println("got ", s.String()) l.Println("got ", s.String())
fileServer.Shutdown(context.Background()) fileServer.Shutdown(context.Background())
bouncer.Shutdown(context.Background()) bouncer.Shutdown(context.Background())
break l break l
case <-time.NewTicker(time.Minute * time.Duration(*interval)).C: case <-time.NewTicker(time.Minute * time.Duration(*interval)).C:
l.Println("tick") genFeeds(ids)
genFeed()
}} }}
} }
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") func genFeed(id string) error {
file, err := os.Create("./feeds/f.xml")
tmpFilename := fmt.Sprintf("./feeds/%s.xml.t", id)
finalFilename := fmt.Sprintf("./feeds/%s.xml", id)
file, err := os.Create(tmpFilename)
if err != nil { if err != nil {
return err return err
} }
defer file.Close() 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, Languge: *lang,
BounceURL: *bounc_url, BounceURL: *bounc_url,
}) })
if err != nil { return err }
return os.Rename(tmpFilename, finalFilename)
} }