This commit is contained in:
parent
53aaf09c76
commit
6fd1850e20
@ -17,6 +17,10 @@ func openDatabase() *mysqlite.Db {
|
||||
databaseSource = "videos.db3"
|
||||
}
|
||||
|
||||
return openDatabaseSource(databaseSource)
|
||||
}
|
||||
|
||||
func openDatabaseSource(databaseSource string) *mysqlite.Db {
|
||||
db, err := mysqlite.OpenDb(databaseSource)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening database: %v", err)
|
||||
|
36
episodes.go
36
episodes.go
@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"gitea.seeseepuff.be/seeseemelk/mysqlite"
|
||||
"log"
|
||||
)
|
||||
|
||||
func CalculateEpisodeNumbers(db *sql.DB) error {
|
||||
func CalculateEpisodeNumbers(db *mysqlite.Db) error {
|
||||
log.Printf("Calculating episode numbers")
|
||||
|
||||
// Start a transaction
|
||||
@ -14,50 +14,50 @@ func CalculateEpisodeNumbers(db *sql.DB) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
defer tx.MustRollback()
|
||||
|
||||
// First find all days that still need episodes numbers
|
||||
rows, err := tx.Query(`
|
||||
query := `
|
||||
select v.upload_date,
|
||||
ifnull(
|
||||
(select max(episode) from videos where upload_date = v.upload_date),
|
||||
substr(upload_date, 6, 2) || substr(upload_date, 9, 2) || '00')
|
||||
from videos v where episode is null group by upload_date`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving rows: %w", err)
|
||||
}
|
||||
from videos v where episode is null group by upload_date
|
||||
`
|
||||
|
||||
// Loop over each year and set the missing episode numbers
|
||||
for rows.Next() {
|
||||
for row := range tx.Query(query).Range(&err) {
|
||||
var uploadDate string
|
||||
var lastEpisode int
|
||||
err = rows.Scan(&uploadDate, &lastEpisode)
|
||||
err = row.Scan(&uploadDate, &lastEpisode)
|
||||
log.Printf("Last episode for %s is %d", uploadDate, lastEpisode)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting row: %w", err)
|
||||
}
|
||||
|
||||
// Find all episodes that need updating
|
||||
episodes, err := tx.Query("select id from videos where upload_date = ? and episode is null order by run, id desc", uploadDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving episodes: %w", err)
|
||||
}
|
||||
query := tx.Query("select id from videos where upload_date = ? and episode is null order by run, id desc").Bind(uploadDate)
|
||||
|
||||
// Update each episode
|
||||
for episodes.Next() {
|
||||
for episode := range query.Range(&err) {
|
||||
var episodeId int
|
||||
err = episodes.Scan(&episodeId)
|
||||
err = episode.Scan(&episodeId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving episode id: %w", err)
|
||||
}
|
||||
|
||||
// Set the episode ID
|
||||
lastEpisode++
|
||||
_, err = tx.Exec("update videos set episode = ? where id = ?", &lastEpisode, &episodeId)
|
||||
err = tx.Query("update videos set episode = ? where id = ?").Bind(&lastEpisode, &episodeId).Exec()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating episode id: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving episodes: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error fetching episodes: %w", err)
|
||||
}
|
||||
|
||||
// Commit all changes
|
||||
|
@ -6,28 +6,22 @@ func TestCalculateEpisodeNumbers(t *testing.T) {
|
||||
db := openDatabaseSource(":memory:")
|
||||
|
||||
// Ensure the DB is empty
|
||||
_, err := db.Exec("delete from videos")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
db.Query("delete from videos").MustExec()
|
||||
|
||||
_, err = db.Exec(`insert into videos (title, url, upload_date, year, episode, run) values
|
||||
db.Query(`insert into videos (title, url, upload_date, year, episode, run) values
|
||||
('Video A', 'a', '2025-01-04', 2025, 10401, 1),
|
||||
('Video D', 'd', '2025-01-05', 2025, null, 2),
|
||||
('Video C', 'c', '2025-01-04', 2025, null, 2),
|
||||
('Video B', 'b', '2025-01-04', 2025, null, 2),
|
||||
('Video E', 'e', '2025-10-01', 2025, null, 3),
|
||||
('Old Video', 'z', '2020-12-31', 2020, 100, 1)`)
|
||||
('Old Video', 'z', '2020-12-31', 2020, 100, 1)`).MustExec()
|
||||
|
||||
err := CalculateEpisodeNumbers(db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = CalculateEpisodeNumbers(db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
rows, err := db.Query("select title, episode from videos where year = 2025")
|
||||
rows, err := db.Query("select title, episode from videos where year = 2025").ScanMulti()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -46,7 +40,7 @@ func TestCalculateEpisodeNumbers(t *testing.T) {
|
||||
for _, expected := range expectedList {
|
||||
var title string
|
||||
var episode int
|
||||
rows.Next()
|
||||
rows.MustNext()
|
||||
err = rows.Scan(&title, &episode)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@ -59,4 +53,5 @@ func TestCalculateEpisodeNumbers(t *testing.T) {
|
||||
t.Errorf("Episode is %d, expected %d for video %s", episode, expected.Episode, title)
|
||||
}
|
||||
}
|
||||
rows.MustFinish()
|
||||
}
|
||||
|
3
go.mod
3
go.mod
@ -5,12 +5,13 @@ go 1.24
|
||||
toolchain go1.24.0
|
||||
|
||||
require (
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.3.0
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.4.0
|
||||
github.com/playwright-community/playwright-go v0.4902.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/deckarep/golang-set/v2 v2.7.0 // indirect
|
||||
github.com/donseba/go-htmx v1.12.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -1,10 +1,12 @@
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.3.0 h1:T2TjZj7hvb3KF0zYf/uzidprcDJIBPFi3QcN+gmyutM=
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.3.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE=
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.4.0 h1:jBj4qsSJCz7XOBakh2Rl4Pggvv5hPpR8iLcvxwdQ4NQ=
|
||||
gitea.seeseepuff.be/seeseemelk/mysqlite v0.4.0/go.mod h1:cgswydOxJjMlNwfcBIXnKjr47LwXnMT9BInkiHb0tXE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.7.0 h1:gIloKvD7yH2oip4VLhsv3JyLLFnC0Y2mlusgcvJYW5k=
|
||||
github.com/deckarep/golang-set/v2 v2.7.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/donseba/go-htmx v1.12.0 h1:7tESER0uxaqsuGMv3yP3pK1drfBUXM6apG4H7/3+IgE=
|
||||
github.com/donseba/go-htmx v1.12.0/go.mod h1:8PTAYvNKf8+QYis+DpAsggKz+sa2qljtMgvdAeNBh5s=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||
|
20
html_debug.go
Normal file
20
html_debug.go
Normal file
@ -0,0 +1,20 @@
|
||||
// / +build !release
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func staticFileServer() http.Handler {
|
||||
return http.FileServer(http.Dir("./static"))
|
||||
}
|
||||
|
||||
func renderTemplate(wr io.Writer) error {
|
||||
templates, err := template.ParseGlob("web/*.gohtml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return templates.Execute(wr, nil)
|
||||
}
|
139
main.go
139
main.go
@ -1,78 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"github.com/playwright-community/playwright-go"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var onlyInstall = flag.Bool("install", false, "install the required browser and do nothing else")
|
||||
flag.Parse()
|
||||
|
||||
options := &playwright.RunOptions{
|
||||
Browsers: []string{"firefox"},
|
||||
}
|
||||
err = playwright.Install(options)
|
||||
if err != nil {
|
||||
log.Panicf("error installing playwright: %v", err)
|
||||
}
|
||||
|
||||
if *onlyInstall {
|
||||
return
|
||||
}
|
||||
|
||||
db := openDatabase()
|
||||
defer db.Close()
|
||||
|
||||
sleepTimeStr := os.Getenv("VIVAPLUS_SLEEPTIME")
|
||||
sleepTime := 15
|
||||
if sleepTimeStr != "" {
|
||||
sleepTime, err = strconv.Atoi(sleepTimeStr)
|
||||
if err != nil {
|
||||
log.Fatalf("error parsing sleep time: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
w := NewWebClient(options)
|
||||
username := os.Getenv("VIVAPLUS_USER")
|
||||
password, err := base64.StdEncoding.DecodeString(os.Getenv("VIVAPLUS_PASS"))
|
||||
if err != nil {
|
||||
log.Fatalf("error decoding password: %v", err)
|
||||
}
|
||||
|
||||
err = w.Login(username, string(password))
|
||||
if err != nil {
|
||||
log.Fatalf("error login in: %v", err)
|
||||
}
|
||||
|
||||
for {
|
||||
err = w.DiscoverAllVideos(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = w.FetchVideoMetadata(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = CalculateEpisodeNumbers(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = DownloadAllVideos(db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Printf("Sleeping %d minutes until next run", sleepTime)
|
||||
time.Sleep(time.Duration(sleepTime) * time.Minute)
|
||||
}
|
||||
//var err error
|
||||
//var onlyInstall = flag.Bool("install", false, "install the required browser and do nothing else")
|
||||
//flag.Parse()
|
||||
//
|
||||
//options := &playwright.RunOptions{
|
||||
// Browsers: []string{"firefox"},
|
||||
//}
|
||||
//err = playwright.Install(options)
|
||||
//if err != nil {
|
||||
// log.Panicf("error installing playwright: %v", err)
|
||||
//}
|
||||
//
|
||||
//if *onlyInstall {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//db := openDatabase()
|
||||
//defer db.Close()
|
||||
//
|
||||
//sleepTimeStr := os.Getenv("VIVAPLUS_SLEEPTIME")
|
||||
//sleepTime := 15
|
||||
//if sleepTimeStr != "" {
|
||||
// sleepTime, err = strconv.Atoi(sleepTimeStr)
|
||||
// if err != nil {
|
||||
// log.Fatalf("error parsing sleep time: %v", err)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//w := NewWebClient(options)
|
||||
//username := os.Getenv("VIVAPLUS_USER")
|
||||
//password, err := base64.StdEncoding.DecodeString(os.Getenv("VIVAPLUS_PASS"))
|
||||
//if err != nil {
|
||||
// log.Fatalf("error decoding password: %v", err)
|
||||
//}
|
||||
//
|
||||
//err = w.Login(username, string(password))
|
||||
//if err != nil {
|
||||
// log.Fatalf("error login in: %v", err)
|
||||
//}
|
||||
//
|
||||
//for {
|
||||
// err = w.DiscoverAllVideos(db)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// err = w.FetchVideoMetadata(db)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// err = CalculateEpisodeNumbers(db)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// err = DownloadAllVideos(db)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// log.Printf("Sleeping %d minutes until next run", sleepTime)
|
||||
// time.Sleep(time.Duration(sleepTime) * time.Minute)
|
||||
//}
|
||||
serveWebview()
|
||||
}
|
||||
|
9
static/style.css
Normal file
9
static/style.css
Normal file
@ -0,0 +1,9 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-transform: uppercase;
|
||||
}
|
11
web/index.gohtml
Normal file
11
web/index.gohtml
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Viva++</title>
|
||||
<link href="/static/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Viva++</h1>
|
||||
</body>
|
||||
</html>
|
24
webview.go
Normal file
24
webview.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func serveWebview() {
|
||||
addr := "localhost:8081"
|
||||
|
||||
log.Printf("Listening on %s", addr)
|
||||
http.Handle("/static/", http.StripPrefix("/static/", staticFileServer()))
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := renderTemplate(w)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
|
||||
err := http.ListenAndServe(addr, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user