hopefully channel working

This commit is contained in:
Balakrishnan Balasubramanian 2022-06-28 15:26:16 -04:00
parent 882f8aea2f
commit e2dc04c233
3 changed files with 81 additions and 61 deletions

View File

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"os" "os"
"sync" "sync"
"gitlab.com/balki/ytui/pubsub"
) )
type DownloadStatus string type DownloadStatus string
@ -22,10 +24,9 @@ type Item struct {
Date string `json:"date"` Date string `json:"date"`
URL string `json:"url"` URL string `json:"url"`
Title string `json:"title"` Title string `json:"title"`
Approved bool `json:"approved"`
Status DownloadStatus `json:"status"` Status DownloadStatus `json:"status"`
FileName string `json:"file_name"` FileName string `json:"file_name"`
Progress string `json:"-"` Pt pubsub.ProgressTracker `json:"-"`
} }
type Jdb struct { type Jdb struct {
@ -37,16 +38,21 @@ type Db struct {
mutex sync.Mutex mutex sync.Mutex
lastId int lastId int
path string path string
index map[string]int
} }
func (d *Db) Add(i Item) int { func (d *Db) Add(i Item) (int, bool) {
d.mutex.Lock() d.mutex.Lock()
defer d.mutex.Unlock() defer d.mutex.Unlock()
if id, ok := d.index[i.URL]; ok {
return id, false
}
i.Id = d.lastId i.Id = d.lastId
d.lastId++ d.lastId++
d.items = append(d.items, i) d.items = append(d.items, i)
d.save() d.save()
return i.Id d.index[i.URL] = i.Id
return i.Id, true
} }
func (d *Db) Update(id int, persist bool, f func(*Item)) error { func (d *Db) Update(id int, persist bool, f func(*Item)) error {
@ -101,14 +107,17 @@ func Load(path string) (*Db, error) {
return nil, err return nil, err
} }
m := 0 m := 0
indexMap := map[string]int{}
for _, item := range jd.Items { for _, item := range jd.Items {
if item.Id > m { if item.Id > m {
m = item.Id m = item.Id
} }
indexMap[item.URL] = item.Id
} }
return &Db{ return &Db{
items: jd.Items, items: jd.Items,
path: path, path: path,
lastId: m + 1, lastId: m + 1,
index: indexMap,
}, nil }, nil
} }

79
main.go
View File

@ -16,6 +16,7 @@ import (
"time" "time"
"gitlab.com/balki/ytui/db" "gitlab.com/balki/ytui/db"
"gitlab.com/balki/ytui/pubsub"
) )
//go:embed templates/index.html //go:embed templates/index.html
@ -29,7 +30,6 @@ var (
videosUrl = "/vids" videosUrl = "/vids"
cachePath = "./cache" cachePath = "./cache"
dbPath = "./db.json" dbPath = "./db.json"
approval bool = false
) )
var d *db.Db var d *db.Db
@ -41,7 +41,6 @@ func parse() {
flag.StringVar(&videosUrl, "videosurl", videosUrl, "Prefix of the url, i.e. https://domain.com/<this var>/<video filename>") flag.StringVar(&videosUrl, "videosurl", videosUrl, "Prefix of the url, i.e. https://domain.com/<this var>/<video filename>")
flag.StringVar(&cachePath, "cachepath", cachePath, "Path where temporary download files are saved") flag.StringVar(&cachePath, "cachepath", cachePath, "Path where temporary download files are saved")
flag.StringVar(&dbPath, "dbpath", dbPath, "Path where downloaded info is saved") flag.StringVar(&dbPath, "dbpath", dbPath, "Path where downloaded info is saved")
flag.BoolVar(&approval, "approval", approval, "Is approval required before allowing to watch")
flag.Parse() flag.Parse()
if ytcmd != ytdlCmd[0] { if ytcmd != ytdlCmd[0] {
ytdlCmd = strings.Fields(ytcmd) ytdlCmd = strings.Fields(ytcmd)
@ -68,12 +67,6 @@ func main() {
log.Panic(err) log.Panic(err)
} }
defer d.Save() defer d.Save()
seen := map[string]struct{}{}
d.Run(func(d *db.Jdb) {
for _, i := range d.Items {
seen[i.URL] = struct{}{}
}
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet { if r.Method == http.MethodGet {
d.Run(func(d *db.Jdb) { d.Run(func(d *db.Jdb) {
@ -89,18 +82,15 @@ func main() {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if _, ok := seen[yturl]; !ok { id, isNew := d.Add(db.Item{
seen[yturl] = struct{}{}
id := d.Add(db.Item{
Date: time.Now().Format("2006-01-02 15:04"), Date: time.Now().Format("2006-01-02 15:04"),
URL: yturl, URL: yturl,
Title: "Loading", Title: "Loading",
Approved: false,
Status: db.NotStarted, Status: db.NotStarted,
}) })
if isNew {
go getTitle(id, yturl) go getTitle(id, yturl)
go download(id, yturl) go download(id, yturl)
} }
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
}) })
@ -123,18 +113,43 @@ func getTitle(id int, yturl string) {
} }
func download(id int, yturl string) { func download(id int, yturl string) {
pt := pubsub.NewProgressTracker()
d.Update(id, true, func(i *db.Item) { d.Update(id, true, func(i *db.Item) {
i.Status = db.InProgress i.Status = db.InProgress
i.Pt = pt
}) })
pc, err := pt.Publish()
defer close(pc)
if err != nil {
log.Panic(err)
}
var status db.DownloadStatus
var fname string
if fname, err = downloadYt(id, yturl, pc); err != nil {
status = db.Error
} else {
status = db.Done
}
d.Update(id, true, func(i *db.Item) {
i.Status = status
i.FileName = fname
})
}
func downloadYt(id int, yturl string, pc chan<- string) (string, error) {
pathTmpl := fmt.Sprintf("%s/video_%d.%%(ext)s", cachePath, id) pathTmpl := fmt.Sprintf("%s/video_%d.%%(ext)s", cachePath, id)
args := append(ytdlCmd, "--newline", "--output", pathTmpl, yturl) args := append(ytdlCmd, "--newline", "--output", pathTmpl, yturl)
cmd := exec.Command(args[0], args[1:]...) cmd := exec.Command(args[0], args[1:]...)
rc, err := cmd.StdoutPipe() rc, err := cmd.StdoutPipe()
if err != nil { if err != nil {
log.Panic(err) pc <- "Pre starting error"
return "", err
} }
defer rc.Close()
pc <- "Starting download"
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
log.Panic(err) pc <- "Start error"
return "", err
} }
br := bufio.NewReader(rc) br := bufio.NewReader(rc)
for { for {
@ -142,33 +157,31 @@ func download(id int, yturl string) {
if err != nil { if err != nil {
break break
} }
d.Update(id, false, func(i *db.Item) { pc <- string(line)
i.Progress = string(line)
})
} }
rc.Close() pc <- "Waiting to complete..."
err = cmd.Wait() err = cmd.Wait()
var status db.DownloadStatus
var fname string var fname string
if err != nil { if err != nil {
status = db.Error pc <- "Download Error"
} else { return "", fmt.Errorf("Download Error, err: %w", err)
status = db.Done }
pc <- "Download Done, renaming"
matches, err := fs.Glob(os.DirFS(cachePath), fmt.Sprintf("video_%d.*", id)) matches, err := fs.Glob(os.DirFS(cachePath), fmt.Sprintf("video_%d.*", id))
if err != nil { if err != nil {
panic(err) pc <- "Match Error"
return "", fmt.Errorf("Glob match error, err: %w\n", err)
} }
if len(matches) != 1 { if len(matches) != 1 {
panic(len(matches)) pc <- "Multiple Match Error"
return "", fmt.Errorf("Got multiple matches, count: %v", len(matches))
} }
fname = matches[0] fname = matches[0]
err = os.Rename(path.Join(cachePath, fname), path.Join(videosPath, fname)) source := path.Join(cachePath, fname)
if err != nil { destination := path.Join(videosPath, fname)
panic(err) if err := os.Rename(source, destination); err != nil {
pc <- "Rename error"
return "", fmt.Errorf("Rename error, fname: %q, source: %q, destination: %q, err: %w\n", fname, source, destination, err)
} }
} return fname, nil
d.Update(id, true, func(i *db.Item) {
i.Status = status
i.FileName = fname
})
} }

View File

@ -29,8 +29,6 @@
<td> <td>
{{ if eq .Status "Done" }} {{ if eq .Status "Done" }}
<a target="_blank" href="{{ vids_prefix }}/{{ .FileName }}">Watch</a> <a target="_blank" href="{{ vids_prefix }}/{{ .FileName }}">Watch</a>
{{ else if eq .Status "InProgress" }}
{{ .Progress }}
{{ else }} {{ else }}
{{ .Status }} {{ .Status }}
{{ end }} {{ end }}