From fae249faae04b64f2b777abf14f0de529afd9bfb Mon Sep 17 00:00:00 2001 From: cdmnky Date: Sat, 25 May 2024 12:05:42 -0400 Subject: [PATCH] Initial commit --- .gitignore | 6 +- patreon-dl/gui/VERSION | 1 + patreon-dl/gui/bin/config.json | 12 ++ patreon-dl/gui/handlers/handlers.go | 27 +++ patreon-dl/gui/handlers/middleware.go | 84 +++++++++ patreon-dl/gui/handlers/mods/funcs.go | 164 ++++++++++++++++++ patreon-dl/gui/handlers/mods/patreon.go | 111 ++++++++++++ patreon-dl/gui/handlers/mods/vimeo.go | 135 ++++++++++++++ patreon-dl/gui/handlers/server.go | 138 +++++++++++++++ patreon-dl/gui/handlers/template.go | 61 +++++++ patreon-dl/gui/local.pkg/src/config/config.go | 64 +++++++ patreon-dl/gui/local.pkg/src/global/global.go | 12 ++ .../gui/local.pkg/src/response/response.go | 42 +++++ .../gui/local.pkg/src/sitevars/sitevars.go | 24 +++ patreon-dl/gui/makefile | 39 +++++ patreon-dl/gui/setenv.sh | 5 + patreon-dl/gui/src/assets.go | 4 + patreon-dl/gui/src/main.go | 49 ++++++ 18 files changed, 976 insertions(+), 2 deletions(-) create mode 100755 patreon-dl/gui/VERSION create mode 100755 patreon-dl/gui/bin/config.json create mode 100755 patreon-dl/gui/handlers/handlers.go create mode 100755 patreon-dl/gui/handlers/middleware.go create mode 100644 patreon-dl/gui/handlers/mods/funcs.go create mode 100644 patreon-dl/gui/handlers/mods/patreon.go create mode 100644 patreon-dl/gui/handlers/mods/vimeo.go create mode 100755 patreon-dl/gui/handlers/server.go create mode 100755 patreon-dl/gui/handlers/template.go create mode 100755 patreon-dl/gui/local.pkg/src/config/config.go create mode 100755 patreon-dl/gui/local.pkg/src/global/global.go create mode 100755 patreon-dl/gui/local.pkg/src/response/response.go create mode 100755 patreon-dl/gui/local.pkg/src/sitevars/sitevars.go create mode 100644 patreon-dl/gui/makefile create mode 100755 patreon-dl/gui/setenv.sh create mode 100755 patreon-dl/gui/src/assets.go create mode 100755 patreon-dl/gui/src/main.go diff --git a/.gitignore b/.gitignore index adf8f72..e5450b3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,13 @@ # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # # Binaries for programs and plugins +*.bin +*.dll +*.dylib *.exe *.exe~ -*.dll +*.manifest *.so -*.dylib # Test binary, built with `go test -c` *.test diff --git a/patreon-dl/gui/VERSION b/patreon-dl/gui/VERSION new file mode 100755 index 0000000..7bcd0e3 --- /dev/null +++ b/patreon-dl/gui/VERSION @@ -0,0 +1 @@ +0.0.2 \ No newline at end of file diff --git a/patreon-dl/gui/bin/config.json b/patreon-dl/gui/bin/config.json new file mode 100755 index 0000000..caf81b6 --- /dev/null +++ b/patreon-dl/gui/bin/config.json @@ -0,0 +1,12 @@ +{ + "thresshold": "1500", + "ffmpegbin": "/usr/bin/ffmpeg", + "templates": [ + { "mask": "Asia BJ, {title}.mp4", "hint": "master.json" } + ,{ "mask": "Mr. Video, {title}.mp4", "hint": "master.json" } + ,{ "mask": "BissFlix, {title}.mp4", "hint": "rendition.m3u8" } + ,{ "mask": "Kat, {title}.mp4", "hint": "rendition.m3u8" } + ,{ "mask": "Millie, {title}.mp4", "hint": "rendition.m3u8" } + ,{ "mask": "Run To The Movies, {title}.mp4", "hint": "rendition.m3u8" } + ] + } diff --git a/patreon-dl/gui/handlers/handlers.go b/patreon-dl/gui/handlers/handlers.go new file mode 100755 index 0000000..5fd6e88 --- /dev/null +++ b/patreon-dl/gui/handlers/handlers.go @@ -0,0 +1,27 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +// Package handlers ... +package handlers + +import ( + "net/http" + "strings" + + "go.cdmnky.io/v2/net/session" +) + +func IsAuthorized(w http.ResponseWriter, r *http.Request, session *session.Manager) string { + + authorized := "no" + // s := session.SessionStart(w, r) + // if s.Get("authorized") != nil { + // authorized = s.Get("authorized").(string) + // } + + return authorized +} + +func IsMobile(userAgent string) bool { + return (strings.Contains(strings.ToLower(userAgent), "android") || + strings.Contains(strings.ToLower(userAgent), "iphone")) +} diff --git a/patreon-dl/gui/handlers/middleware.go b/patreon-dl/gui/handlers/middleware.go new file mode 100755 index 0000000..d9add3d --- /dev/null +++ b/patreon-dl/gui/handlers/middleware.go @@ -0,0 +1,84 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +package handlers + +import ( + "database/sql" + "fmt" + "net/http" + "net/url" + "time" + + "cdmnky.io/net/patreon-ui/local.pkg/src/response" + "cdmnky.io/net/patreon-ui/local.pkg/src/sitevars" + + "go.cdmnky.io/v2/net/router" + "go.cdmnky.io/v2/net/session" +) + +// Unauthorized ... +func Unauthorized(w http.ResponseWriter) { + resp := response.New(fmt.Sprintf("%v", http.StatusUnauthorized), "Unauthorized", []byte{}) + data, _ := resp.ToJSON() + + w.WriteHeader(http.StatusUnauthorized) + w.Write(data) +} + +// Public ... +func Public(h router.Handle, db *sql.DB, s *session.Manager) router.Handle { + return router.Handle(func(w http.ResponseWriter, r *http.Request, p url.Values) { + t1 := time.Now() + + // session := s.SessionStart(w, r) + // if session.Get("token") != nil { + // token := session.Get("token").(string) + // obj := user.New() + // obj.Token = token + // cnt, _ := obj.Db(db).Where(obj).Debug(false).Count() + // if cnt == 0 { + // s.SessionDestroy(w, r) + // } + // } + + h(w, r, p) + + t2 := time.Now() + + var realIP = r.Header.Get("X-Real-IP") + if len(realIP) == 0 { + realIP = r.RemoteAddr + } + var userAgent = r.Header.Get("User-Agent") + var referrer = r.Header.Get("Referer") + now := time.Now() + mask := "2006/01/02 15:04:05" + fmt.Printf("%s|%s|%s|%s|%s|%s|%v\n", now.Format(mask), realIP, r.Method, r.URL.String(), userAgent, referrer, t2.Sub(t1)) + }) +} + +// Secured ... +func Secured(h router.Handle, db *sql.DB, s *session.Manager, sitevars *sitevars.Sitevars) router.Handle { + return router.Handle(func(w http.ResponseWriter, r *http.Request, p url.Values) { + + authorized := false + + // session := s.SessionStart(w, r) + // if session.Get("token") != nil { + // token := session.Get("token").(string) + // obj := user.New() + // obj.Token = token + // cnt, _ := obj.Db(db).Where(obj).Debug(false).Count() + // if cnt == 1 { + // authorized = true + // } + // } + + if authorized { + h(w, r, p) + } else { + Unauthorized(w) + } + + }) +} diff --git a/patreon-dl/gui/handlers/mods/funcs.go b/patreon-dl/gui/handlers/mods/funcs.go new file mode 100644 index 0000000..90516a5 --- /dev/null +++ b/patreon-dl/gui/handlers/mods/funcs.go @@ -0,0 +1,164 @@ +package mods + +import ( + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + + "go.cdmnky.io/v2/fs" + "go.cdmnky.io/v2/str" + "go.cdmnky.io/v2/utils" +) + +func Format(format string, i ...any) string { + return fmt.Sprintf(format, i...) +} + +func ProcessVideo(videoURL, videofile string) (err error) { + + fmt.Printf("Fetching video data into file '%s'... ", videofile) + data, err := Dload(videoURL) + if err != nil { + return err + } + + if err = os.WriteFile(videofile, data, 0600); err != nil { + return err + } + fmt.Println("Complete!") + + return nil +} + +func Dload(src string) (data []byte, err error) { + + client := &http.Client{} + req, _ := http.NewRequest("GET", src, nil) + + res, err := client.Do(req) + if err != nil { + log.Fatal(err) + } + if res.StatusCode == 200 { + data, err = io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + return nil, err + } + } else { + err = fmt.Errorf("errcode: %d", res.StatusCode) + return nil, err + } + + return data, nil +} + +func Encode(ffmpeg string, files []string) (err error) { + + if !fs.FileExists(ffmpeg) { + return fmt.Errorf("ffmpeg binary not found: %s", ffmpeg) + } + ratio := "1280x720" + + for _, file := range files { + encfile := fmt.Sprintf("/tmp/%s.mp4", str.Random(12)) + fmt.Printf("Encoding (%s) '%s'\n", ratio, encfile) + args := []string{ + "-i", + file, + "-s", ratio, + "-vcodec", "h264", + "-acodec", "aac", + encfile, + } + cmd := exec.Command(ffmpeg, args...) + + err = cmd.Start() + if err != nil { + return + } + + err = cmd.Wait() + if err != nil { + return + } + + os.Rename(encfile, file) + } + + return nil +} + +func GetFileSize(label, filename string) int64 { + + fh, err := os.OpenFile(filename, os.O_RDONLY, os.ModeTemporary) + if err != nil { + log.Println(err) + } + defer fh.Close() + + fi, err := fh.Stat() + if err != nil { + log.Println(err) + os.Exit(1) + } + fmt.Printf("%s: %s (%s)\n", label, filename, utils.GetHumanSize(fi.Size())) + + return fi.Size() +} + +func ProcessAudio(URL, audiofile string) (err error) { + + fmt.Printf("Fetching audio data into file '%s'... ", audiofile) + data, err := Dload(URL) + if err != nil { + return err + } + + if err = os.WriteFile(audiofile, data, 0600); err != nil { + return err + } + fmt.Println("Complete!") + + return +} + +func Merge(ffmpeg, videofile, audiofile, tmpfile string) (err error) { + + if !fs.FileExists(ffmpeg) { + return fmt.Errorf("ffmpeg binary not found: %s", ffmpeg) + } + if !fs.FileExists(videofile) { + return fmt.Errorf("work file not found: %s", videofile) + } + if !fs.FileExists(audiofile) { + return fmt.Errorf("work file not found: %s", audiofile) + } + + args := []string{ + "-i", + videofile, + "-i", + audiofile, + "-c:v", + "copy", + "-c:a", + "aac", + tmpfile, + } + cmd := exec.Command(ffmpeg, args...) + err = cmd.Start() + if err != nil { + return + } + + err = cmd.Wait() + if err != nil { + return + } + + return nil +} diff --git a/patreon-dl/gui/handlers/mods/patreon.go b/patreon-dl/gui/handlers/mods/patreon.go new file mode 100644 index 0000000..d20e8b3 --- /dev/null +++ b/patreon-dl/gui/handlers/mods/patreon.go @@ -0,0 +1,111 @@ +package mods + +import ( + "fmt" + "os" + "strings" + "time" + + "cdmnky.io/net/patreon-ui/local.pkg/src/config" + "go.cdmnky.io/v2/str" + "go.cdmnky.io/v2/utils" +) + +func ProcPatreon(fn func(string), config *config.Config, playlistURL string, outfile string, maxSize int64) { + + sleepTimeout := 5 + + //postProcessScript := "" + tmpfile := Format("/tmp/%s.mp4", str.Random(12)) + + interval := 0 + + data, err := Dload(playlistURL) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + playlist := string(data) + lines := strings.Split(playlist, "\n") + + now := time.Now() + + parts := []string{} + for _, line := range lines { + if len(line) > 0 && line[0:1] != "#" { + parts = append(parts, line) + } + } + + fh, err := os.Create(tmpfile) + if err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + defer func() { + fmt.Printf("Closing file '%s'", tmpfile) + fh.Close() + if err != nil { + fn(Format("%v", err)) + os.Exit(1) + } + time.Sleep(time.Duration(sleepTimeout) * time.Second) + fmt.Println("Complete!") + }() + + cnt := 1 + for _, part := range parts { + fmt.Printf("Temp file............. %s\n", tmpfile) + fmt.Printf("Outfile............... %s\n", outfile) + fmt.Printf("Timeout............... %d\n", interval) + fmt.Printf("# of parts to fetch... %d\n", len(parts)) + fmt.Printf("Writing to file '%s'\n", tmpfile) + + fn(Format("Fetching part %d of %d...", cnt, len(parts))) + data, err := Dload(part) + if err != nil && err.Error() == "errcode: 403" { + _, err = fh.Write(data) + if err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + break + } + + _, err = fh.Write(data) + if err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + + if interval > 0 { + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + cnt++ + } + + fileSize := GetFileSize("Temp file", tmpfile) + if maxSize > 0 && fileSize > int64(maxSize) { + if err = Encode(config.FFMpegBin, []string{tmpfile}); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + } else { + fmt.Printf("File size (%v) does not exceed max file size (%v); continuing...\n", fileSize, maxSize) + } + + fmt.Printf("Renaming '%s' to '%s'\n", tmpfile, outfile) + os.Rename(tmpfile, outfile) + + GetFileSize("Output file", outfile) + + //if len(postProcessScript) > 0 { + // execute(postProcessScript, outfile) + //} + + elapsedTime := utils.ElapsedTime(now) + fmt.Printf("Elapsed time: %s\n", elapsedTime) + fmt.Printf("Download complete. Filename: '%s', Elapsed time: %s\n", outfile, elapsedTime) + fn(Format("Complete. Elapsed time: %s\n", elapsedTime)) +} diff --git a/patreon-dl/gui/handlers/mods/vimeo.go b/patreon-dl/gui/handlers/mods/vimeo.go new file mode 100644 index 0000000..68bd0a2 --- /dev/null +++ b/patreon-dl/gui/handlers/mods/vimeo.go @@ -0,0 +1,135 @@ +package mods + +import ( + "fmt" + "net/url" + "os" + "strconv" + "strings" + "time" + + "cdmnky.io/net/patreon-ui/local.pkg/src/config" + vimeo "cdmnky.io/net/vimeo/pkg.local/vimeo/src" + "go.cdmnky.io/v2/str" + "go.cdmnky.io/v2/utils" +) + +func ProcVimeo(fn func(string), config *config.Config, playlistURL string, outfile string, maxSize int64) { + + sleepTimeout := 5 + + videofile := fmt.Sprintf("/tmp/%s.mp4", str.Random(12)) + audiofile := fmt.Sprintf("/tmp/%s.mp3", str.Random(12)) + tmpfile := fmt.Sprintf("/tmp/%s.mp4", str.Random(12)) + encfile := fmt.Sprintf("/tmp/%s.mp4", str.Random(12)) + idxStart := "1" + + now := time.Now() + + fmt.Printf("Work Video File............. %s\n", videofile) + fmt.Printf("Work Audio File............. %s\n", audiofile) + fmt.Printf("Work Temp File.............. %s\n", tmpfile) + fmt.Printf("Work Encoded File........... %s\n", encfile) + fmt.Printf("Start Index................. %s\n", idxStart) + fmt.Printf("Outfile..................... %s\n", outfile) + + data, err := Dload(playlistURL) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + objVimeo := vimeo.Vimeo{} + _, err = objVimeo.Unmarshal(data) + if err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + + playlistURL = playlistURL[:strings.Index(playlistURL, "?")] + baseURL, _ := url.JoinPath(playlistURL, "../", objVimeo.BaseURL) + _ = baseURL + + success := 0 + + idxs, err := strconv.Atoi(idxStart) + if err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + fmt.Println("Fetching video data") + time.Sleep(3 * time.Second) + for idx := idxs; idx < len(objVimeo.Video); idx++ { + URL, _ := url.JoinPath(baseURL, objVimeo.Video[idx].BaseURL, objVimeo.Video[idx].IndexSegment) + fmt.Printf("Trying [%d/%d] %s...\n", idx, len(objVimeo.Video), objVimeo.Video[idx].ID) + fn(Format("Fetching video data: Trying [%d/%d] %s...", idx, len(objVimeo.Video), objVimeo.Video[idx].ID)) + if err := ProcessVideo(URL, videofile); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } else { + success++ + break + } + } + GetFileSize("Video file", videofile) + + fmt.Println("Fetching audio data") + time.Sleep(3 * time.Second) + for idx := 1; idx < len(objVimeo.Audio); idx++ { + URL, _ := url.JoinPath(baseURL, objVimeo.Audio[idx].BaseURL, objVimeo.Audio[idx].IndexSegment) + fmt.Printf("Trying [%d/%d] %s...\n", idx+1, len(objVimeo.Audio), objVimeo.Audio[idx].ID) + fn(Format("Fetching audio data: Trying [%d/%d] %s...", idx+1, len(objVimeo.Audio), objVimeo.Audio[idx].ID)) + if err := ProcessAudio(URL, audiofile); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } else { + success++ + break + } + } + GetFileSize("Audio file", audiofile) + + if success != 2 { + os.Exit(1) + } + + fmt.Printf("Merging audio/video data into temp file '%s'...\n", tmpfile) + fn(Format("Merging audio/video data into temp file '%s'...", tmpfile)) + if err = Merge(config.FFMpegBin, videofile, audiofile, tmpfile); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + + fileSize := GetFileSize("Temp file", tmpfile) + if maxSize > 0 && fileSize > int64(maxSize) { + if err = Encode(config.FFMpegBin, []string{tmpfile}); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + } else { + fmt.Println("File size does not exceed max file size; continuing...") + } + + fmt.Printf("Renaming '%s' to '%s'...\n", tmpfile, outfile) + os.Rename(tmpfile, outfile) + GetFileSize("Output file", outfile) + + //if override || x.Prompt("Cleanup work files (y/n)? ") == "y" { + fmt.Printf("Removing '%s'...\n", videofile) + if err = os.Remove(videofile); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + fmt.Printf("Removing '%s'...\n", audiofile) + if err = os.Remove(audiofile); err != nil { + fn(Format("Error: %v", err)) + time.Sleep(time.Duration(sleepTimeout) * time.Second) + } + //} + + elapsedTime := utils.ElapsedTime(now) + fmt.Printf("Elapsed time: %s\n", elapsedTime) + + fmt.Printf("Download complete. Filename: '%s', Elapsed time: %s", outfile, elapsedTime) + fn(Format("Complete. Elapsed time: %s\n", elapsedTime)) +} diff --git a/patreon-dl/gui/handlers/server.go b/patreon-dl/gui/handlers/server.go new file mode 100755 index 0000000..484ef93 --- /dev/null +++ b/patreon-dl/gui/handlers/server.go @@ -0,0 +1,138 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +package handlers + +import ( + "fmt" + "strconv" + "strings" + + "cdmnky.io/net/patreon-ui/handlers/mods" + "cdmnky.io/net/patreon-ui/local.pkg/src/config" + "github.com/roblillack/spot" + "github.com/roblillack/spot/ui" +) + +// NewServer ... +func NewServer(config *config.Config) *Server { + return &Server{ + config: config, + } +} + +// Server ... +type Server struct { + config *config.Config +} + +// Start ... +func (x *Server) Start() { + ui.Init() + + height := 260 + width := 600 + profileIdx := 0 + + spot.MountFn(func(ctx *spot.RenderContext) spot.Component { + + hints := map[string]string{} + profiles := []string{} + for _, t := range x.config.Templates { + profiles = append(profiles, t.Mask) + hints[t.Mask] = t.Hint + } + + filename, setFilename := spot.UseState[string](ctx, "") + lblFilename := &ui.Label{ + X: 5, Y: 213, Width: width - 10, Height: 20, Value: filename, + } + + status, showStatus := spot.UseState[string](ctx, fmt.Sprintf("Hint: %s", hints[profiles[profileIdx]])) + lblStatus := &ui.Label{ + X: 5, Y: 235, Width: width - 10, Height: 20, Value: status, + } + + cmbProfile := &ui.Dropdown{ + X: 5, Y: 5, Width: width - 10, Height: 20, Items: profiles, Editable: false, SelectedIndex: profileIdx, + OnSelectionDidChange: func(idx int) { + profileIdx = idx + showStatus(fmt.Sprintf("Hint: %s", hints[profiles[idx]])) + }, + } + + lblVideoURL := &ui.Label{ + X: 5, Y: 30, Width: width - 10, Height: 20, Value: "Video URL:", + } + videoURL := "" + videoURL, setVideoURL := spot.UseState[string](ctx, "") + txtVideeoURL := &ui.TextField{ + X: 5, Y: 50, Width: width - 10, Height: 20, Value: videoURL, + OnChange: func(value string) { setVideoURL(value) }, + } + + lblVideoTitle := &ui.Label{ + X: 5, Y: 80, Width: width - 10, Height: 20, Value: "Video Title:", + } + videoTitle, setVideoTitle := spot.UseState[string](ctx, "") + txtVideeoTitle := &ui.TextField{ + X: 5, Y: 100, Width: width - 10, Height: 20, Value: videoTitle, + OnChange: func(value string) { setVideoTitle(value) }, + } + + lblThreshhold := &ui.Label{ + X: 5, Y: 130, Width: width - 10, Height: 20, Value: "Size in MB to trigger re-encoding (0 for none)", + } + thresshold, setThresshold := spot.UseState[string](ctx, x.config.Thresshold) + txtThresshold := &ui.TextField{ + X: 5, Y: 150, Width: width - 10, Height: 20, Value: thresshold, + OnChange: func(value string) { setThresshold(value) }, + } + + btnProcess := &ui.Button{ + X: 5, Y: 180, Width: width - 10, Height: 25, + Title: "Process Download", + OnClick: func() { + + mask := profiles[profileIdx] + title := videoTitle + url := videoURL + threshold, err := strconv.ParseInt(thresshold, 0, 64) + if err != nil { + showStatus(mods.Format("Error: %v", err)) + return + } + threshold = threshold * (1000 * 1000) + mask = strings.Replace(mask, "{title}", title, -1) + setFilename(mods.Format("Output file: %s", mask)) + + //if strings.Contains(url, "akamaized.net") { + if strings.Contains(url, "vimeocdn.com") { + go mods.ProcVimeo(showStatus, x.config, url, mask, threshold) + } else { + go mods.ProcPatreon(showStatus, x.config, url, mask, threshold) + } + + }, + } + + return &ui.Window{ + Title: x.config.Appname, + Width: width, + Height: height, + Children: []spot.Component{ + cmbProfile, + lblVideoURL, + txtVideeoURL, + lblVideoTitle, + txtVideeoTitle, + lblThreshhold, + txtThresshold, + btnProcess, + lblFilename, + lblStatus, + }, + } + }) + + ui.Run() +} diff --git a/patreon-dl/gui/handlers/template.go b/patreon-dl/gui/handlers/template.go new file mode 100755 index 0000000..e53d250 --- /dev/null +++ b/patreon-dl/gui/handlers/template.go @@ -0,0 +1,61 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +package handlers + +import ( + "database/sql" + "net/http" + "net/url" + + "cdmnky.io/net/patreon-ui/local.pkg/src/sitevars" + + "go.cdmnky.io/v2/net/assets" + "go.cdmnky.io/v2/net/router" + "go.cdmnky.io/v2/net/session" +) + +// NewTemplate ... +func NewTemplate( + db *sql.DB, + assets *assets.Assets, + session *session.Manager, + sitevars *sitevars.Sitevars, +) *Template { + return &Template{db: db, assets: assets, session: session, sitevars: sitevars} +} + +// Register ... +func (x *Template) Register(r *router.Router) { + r.Handle("POST", "/template", x.Create) + r.Handle("GET", "/template", x.Read) + r.Handle("PUT", "/template", x.Update) + r.Handle("DELETE", "/template", x.Delete) +} + +// Template ... +type Template struct { + db *sql.DB + assets *assets.Assets + session *session.Manager + sitevars *sitevars.Sitevars +} + +// Create ... +func (x *Template) Create(w http.ResponseWriter, r *http.Request, params url.Values) { + w.Write([]byte{}) +} + +// Read ... +func (x *Template) Read(w http.ResponseWriter, r *http.Request, params url.Values) { + w.Write([]byte{}) +} + +// Update ... +func (x *Template) Update(w http.ResponseWriter, r *http.Request, params url.Values) { + w.Write([]byte{}) +} + +// Delete ... +func (x *Template) Delete(w http.ResponseWriter, r *http.Request, params url.Values) { + w.Write([]byte{}) +} diff --git a/patreon-dl/gui/local.pkg/src/config/config.go b/patreon-dl/gui/local.pkg/src/config/config.go new file mode 100755 index 0000000..8d74bab --- /dev/null +++ b/patreon-dl/gui/local.pkg/src/config/config.go @@ -0,0 +1,64 @@ +// auto generated by cdgen, 2019.05.1 on Wednesday Jun 12 @ 6:40PM +// source file: database/config.json + +/* + * This is free and unencumbered software released into the public + * domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * The complete license can be found in the UNLICENSE file. + * + * Vim: + * set foldmethod=marker + * set shiftwidth=2 + * set smartcase + * set tabstop=2 + */ + +package config + +import ( + "encoding/json" +) + +// Config models the table config +type Config struct { + Appname string `json:"-"` + Thresshold string `json:"thresshold"` + FFMpegBin string `json:"ffmpegbin"` + Templates []Template `json:"templates"` +} + +type Template struct { + Mask string `json:"mask"` + Hint string `json:"hint"` +} + +// New ... +func New() *Config { + return &Config{ + Templates: []Template{ + { + Mask: "Creator Name, {title}", + Hint: "URL: master.json", + }, + }, + FFMpegBin: "/usr/bin/ffmpeg", + } +} + +// ToJSON ... +func (x *Config) ToJSON() (data []byte, err error) { + data, err = json.MarshalIndent(x, " ", " ") + return +} + +// Parse ... +func (x *Config) Parse(data []byte) (err error) { + err = json.Unmarshal(data, x) + return +} diff --git a/patreon-dl/gui/local.pkg/src/global/global.go b/patreon-dl/gui/local.pkg/src/global/global.go new file mode 100755 index 0000000..b0d78f1 --- /dev/null +++ b/patreon-dl/gui/local.pkg/src/global/global.go @@ -0,0 +1,12 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +// Package global ... +package global + +var ( + // DateFormat ... + DateFormat = "2006-01-02 15:04:05 -0700 UTC" + + // ConfigFileName ... + ConfigFileName = "./config.json" +) diff --git a/patreon-dl/gui/local.pkg/src/response/response.go b/patreon-dl/gui/local.pkg/src/response/response.go new file mode 100755 index 0000000..a8291b3 --- /dev/null +++ b/patreon-dl/gui/local.pkg/src/response/response.go @@ -0,0 +1,42 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +// Package response ... +package response + +import ( + "encoding/json" +) + +// Return codes +const ( + OK = "200" + ERROR = "500" +) + +// New ... +func New(code string, message string, data []byte) *Response { + return &Response{ + Code: code, + Message: message, + Data: data, + } +} + +// Response ... +type Response struct { + Code string `json:"code"` + Message string `json:"message"` + Data []byte `json:"json"` +} + +// ToJSON ... +func (x *Response) ToJSON() (data []byte, err error) { + data, err = json.Marshal(x) + return +} + +// Parse ... +func (x *Response) Parse(data []byte) (err error) { + err = json.Unmarshal(data, x) + return +} diff --git a/patreon-dl/gui/local.pkg/src/sitevars/sitevars.go b/patreon-dl/gui/local.pkg/src/sitevars/sitevars.go new file mode 100755 index 0000000..d45e0eb --- /dev/null +++ b/patreon-dl/gui/local.pkg/src/sitevars/sitevars.go @@ -0,0 +1,24 @@ +// Copyright 2024 Brian Newman. All rights reserved. + +// Package sitevars ... +package sitevars + +import ( + "html/template" + + "cdmnky.io/net/patreon-ui/local.pkg/src/config" +) + +// Sitevars ... +type Sitevars struct { + Sitename string `json:"sitename"` + Copyright string `json:"copyright"` + Port string `json:"port"` + Dbfile string `json:"dbfile"` + Templates []config.Template `json:"templates"` +} + +// GetCopyright ... +func (x *Sitevars) GetCopyright() template.HTML { + return template.HTML(x.Copyright) +} diff --git a/patreon-dl/gui/makefile b/patreon-dl/gui/makefile new file mode 100644 index 0000000..9c260fe --- /dev/null +++ b/patreon-dl/gui/makefile @@ -0,0 +1,39 @@ +# Copyright 2024 Brian Newman. All rights reserved. +# ################################################################################ +# GOARCH=amd64 GOOS=windows go build -o ${BINNAME}-linux-${VERSION}.exe -ldflags "-X main.appname=${BINNAME} -X main.version=${VERSION}" *.go +# rm ${BINNAME}-linux-${VERSION}.exe +# ################################################################################ +APPNAME := patreon-ui +BINNAME := io.cdmnky.net.patreon-ui +VERSION := $(shell cat VERSION) +BUILD := $(shell date +"%Y.%m.%d") +LINKNAME := ${HOME}/.bin/patreon-ui/patreon-ui + +build: + ./local.bin/io.cdmnky.dev.mkassets -d webassets/ -o ./src/assets.go + GOARCH=amd64 GOOS=linux go build -o ./bin/${BINNAME}-linux-${VERSION}.bin -ldflags "-X main.appname=${APPNAME} -X main.version=${VERSION} -X main.build=${BUILD}" ./src/*.go + ./local.bin/io.cdmnky.dev.mkassets -d /dev/null -o ./src/assets.go + +run: + GOARCH=amd64 GOOS=linux go build -o ./bin/${BINNAME} ./src/*.go + clear; ./bin/${BINNAME} + +install: +ifneq ("$(wildcard $(LINKNAME))","") + rm ${LINKNAME} +endif + cp ./bin/${BINNAME}-linux-${VERSION}.bin ${HOME}/.bin/patreon-ui/ + ln -s ${HOME}/.bin/patreon-ui/${BINNAME}-linux-${VERSION}.bin ${LINKNAME} + +clean: + go clean +ifneq ("$(wildcard assets.go)","") + rm assets.go* +endif +ifneq ("$(wildcard ./bin/${BINNAME}-linux-${VERSION}.bin)","") + rm ./bin/${BINNAME}-linux-${VERSION}.bin +endif +ifneq ("$(wildcard ./bin/${BINNAME})","") + rm ./bin/${BINNAME} +endif +all: build diff --git a/patreon-dl/gui/setenv.sh b/patreon-dl/gui/setenv.sh new file mode 100755 index 0000000..d74926c --- /dev/null +++ b/patreon-dl/gui/setenv.sh @@ -0,0 +1,5 @@ +# Copyright 2024 Brian Newman. All rights reserved. +PS1="\u@\W) " +export GOPATH="$GOPATH:`pwd`/local.pkg" +export GO111MODULE=off + diff --git a/patreon-dl/gui/src/assets.go b/patreon-dl/gui/src/assets.go new file mode 100755 index 0000000..72a1431 --- /dev/null +++ b/patreon-dl/gui/src/assets.go @@ -0,0 +1,4 @@ +package main + +var mapOfAssets = map[string]string{ +} diff --git a/patreon-dl/gui/src/main.go b/patreon-dl/gui/src/main.go new file mode 100755 index 0000000..ab65fc0 --- /dev/null +++ b/patreon-dl/gui/src/main.go @@ -0,0 +1,49 @@ +// Copyright 2024 Brian Newman. All rights reserved. +/* + A few words about this application. +*/ +package main + +import ( + "fmt" + "log" + "os" + "path" + "path/filepath" + + "cdmnky.io/net/patreon-ui/handlers" + "cdmnky.io/net/patreon-ui/local.pkg/src/config" + "cdmnky.io/net/patreon-ui/local.pkg/src/global" +) + +var ( + appname = "template" + version = "xx.yy.zz" + build = "yyyy.mm.dd" + + globConfig *config.Config +) + +func main() { + + // Load config.json values + // ----------------------------------------------------------------------------- + binpath, _ := os.Executable() + binpath = path.Dir(binpath) + data, err := os.ReadFile(filepath.Join(binpath, global.ConfigFileName)) + if err != nil { + log.Fatal(err) + os.Exit(1) + } + globConfig = config.New() + err = globConfig.Parse(data) + if err != nil { + log.Fatal(err) + os.Exit(1) + } + globConfig.Appname = fmt.Sprintf("%s v%s, %s", appname, version, build) + + (handlers.NewServer( + globConfig, + )).Start() +}