diff --git a/.env.example b/.env.example index 188a44d..9a78fbd 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,4 @@ PIPED_USERNAME="johndoe" PIPED_PASSWORD="supersecurepass" PIPED_API_URL="https://pipedapi.kavin.rocks" QUERY_WAIT_TIME="10000" +QUERY_CRON="0 12 * * *" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..61057b3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Use Go 1.23 bookworm as base image +FROM golang:1.23.4-alpine AS base + +# Move to working directory /build +WORKDIR /build + +# Copy the go.mod and go.sum files to the /build directory +COPY go.mod go.sum ./ + +# Install dependencies +RUN go mod download + +# Copy the entire source code into the container +COPY . . + +# Build the application +RUN go build -o piped-refresher + +# Start the application +CMD ["/build/piped-refresher"] + diff --git a/go.mod b/go.mod index e34ea69..8b288aa 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,11 @@ module git.ghoscht.com/ghoscht/piped-refresher go 1.22.10 -require github.com/joho/godotenv v1.5.1 // indirect +require ( + github.com/go-co-op/gocron/v2 v2.14.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect +) diff --git a/go.sum b/go.sum index d61b19e..a42ab9a 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,12 @@ +github.com/go-co-op/gocron/v2 v2.14.0 h1:bWPJeIdd4ioqiEpLLD1BVSTrtae7WABhX/WaVJbKVqg= +github.com/go-co-op/gocron/v2 v2.14.0/go.mod h1:ZF70ZwEqz0OO4RBXE1sNxnANy/zvwLcattWEFsqpKig= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= diff --git a/main.go b/main.go index a672e8b..b521b14 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/go-co-op/gocron/v2" "github.com/joho/godotenv" "log" "math/rand/v2" @@ -100,23 +101,8 @@ func randomize[S any](slice []S) { } } -func main() { - err := godotenv.Load() - - if err != nil { - fmt.Println("Couldn't find a .env file, assuming already present environment variables") - } - - var username string = os.Getenv("PIPED_USERNAME") // piped username - var password string = os.Getenv("PIPED_PASSWORD") // piped password - var basePath string = os.Getenv("PIPED_API_URL") // piped API URL - maxWaitTime, err := strconv.Atoi(os.Getenv("QUERY_WAIT_TIME")) // in milliseconds, change for potential ban evasion - if err != nil { - panic(err) - } - - fmt.Printf("Logged in as %s on Piped instance %s\n\n", username, basePath) - +// Update Piped videos for all subscriptions given the Piped instance and the matching login data +func update(basePath string, maxWaitTime int, username string, password string) { authResult := login(basePath, username, password) subscriptions := getSubscriptions(basePath, authResult.Token) @@ -132,3 +118,63 @@ func main() { time.Sleep(randomWaitTime) } } + +func main() { + err := godotenv.Load() + + if err != nil { + fmt.Println("Couldn't find a .env file, assuming already present environment variables") + } + + var username string = os.Getenv("PIPED_USERNAME") // piped username + var password string = os.Getenv("PIPED_PASSWORD") // piped password + var basePath string = os.Getenv("PIPED_API_URL") // piped API URL + var cronSchedule string = os.Getenv("QUERY_CRON") // cron schedule how often update should be triggered + maxWaitTime, err := strconv.Atoi(os.Getenv("QUERY_WAIT_TIME")) // in milliseconds, change for potential ban evasion + if err != nil { + panic(err) + } + + fmt.Printf("Logging in as %s on Piped instance %s\n", username, basePath) + + var infinityDuration time.Duration = 42069 * time.Hour // basically infinity + + // create a scheduler + s, err := gocron.NewScheduler(gocron.WithStopTimeout(infinityDuration)) // we don't want the lengthy update task to time out + if err != nil { + panic(err) + } + + // add a job to the scheduler + _, err = s.NewJob( + gocron.CronJob( + cronSchedule, + false, + ), + gocron.NewTask( + func() { + update(basePath, maxWaitTime, username, password) + }, + ), + gocron.WithSingletonMode(gocron.LimitModeReschedule), + ) + if err != nil { + panic(err) + } + + // start the scheduler + s.Start() + + fmt.Print("Starting scheduler...\n\n") + + // block until you are ready to shut down + select { + case <-time.After(time.Minute): + } + + // when you're done, shut it down + err = s.Shutdown() + if err != nil { + panic(err) + } +}