diff --git a/cmd/fapesnap/main.go b/cmd/fapesnap/main.go index 119f8b6..6c995f5 100644 --- a/cmd/fapesnap/main.go +++ b/cmd/fapesnap/main.go @@ -14,6 +14,7 @@ func initRootCmd() *cobra.Command { rootCmd.AddCommand(providers.InitFapelloCmd()) rootCmd.AddCommand(providers.InitFapodropCmd()) + rootCmd.AddCommand(providers.InitBunkrCmd()) return rootCmd } diff --git a/cmd/fapesnap/providers/bunkr.go b/cmd/fapesnap/providers/bunkr.go new file mode 100644 index 0000000..116ef3c --- /dev/null +++ b/cmd/fapesnap/providers/bunkr.go @@ -0,0 +1,36 @@ +package providers + +import ( + "fapesnap/internal/downloader" + "fapesnap/pkg/providers/bunkr" + "log" + + "github.com/spf13/cobra" +) + +func InitBunkrCmd() *cobra.Command { + bunkrCmd := &cobra.Command{ + Use: "bunkr", + Short: "Download photos from bunkr", + Run: func(cmd *cobra.Command, _ []string) { + album, _ := cmd.Flags().GetString("album") + + bunkrProvider := bunkr.Provider{Album: album} + bunkrProvider.InitProvider() + + downloader := downloader.Downloader{PhotosProvider: &bunkrProvider} + err := downloader.DownloadPhotos() + if err != nil { + log.Fatal(err) + } + }, + } + + bunkrCmd.Flags().StringP("album", "a", "", "Bunkr album ID") + + if err := bunkrCmd.MarkFlagRequired("album"); err != nil { + log.Fatal(err) + } + + return bunkrCmd +} diff --git a/internal/downloader/downloader.go b/internal/downloader/downloader.go index 65bfb35..f37e0d9 100644 --- a/internal/downloader/downloader.go +++ b/internal/downloader/downloader.go @@ -26,7 +26,7 @@ type PhotosProvider interface { GetFileName(src string) string GetPhotoURL(photoID string) (string, error) GetPhotos() ([]string, error) - GetRecentPhotoID() (int, error) + GetRecentPhotoID() (string, error) } type Downloader struct { diff --git a/pkg/providers/bunkr/bunkr.go b/pkg/providers/bunkr/bunkr.go new file mode 100644 index 0000000..e95b9ed --- /dev/null +++ b/pkg/providers/bunkr/bunkr.go @@ -0,0 +1,128 @@ +package bunkr + +import ( + "fmt" + "net/url" + "strings" + + "github.com/gocolly/colly" +) + +type Provider struct { + Album string + ProviderName string + BaseURL string +} + +func (p *Provider) InitProvider() { + p.ProviderName = "bunkr" + p.BaseURL = "https://bunkr.si" +} + +func (p *Provider) GetProviderName() string { + return p.ProviderName +} + +func (p *Provider) GetCollectionName() string { + return p.Album +} + +func (p *Provider) GetPhotoURL(photoID string) (string, error) { + photoPageURL, err := url.JoinPath(p.BaseURL, "i", photoID) + if err != nil { + return "", err + } + + c := colly.NewCollector() + + photoURL := "" + + c.OnHTML(".lightgallery img", func(e *colly.HTMLElement) { + if src := e.Attr("src"); src != "" { + photoURL = src + } + }) + + c.Visit(photoPageURL) + + if photoURL == "" { + return "", fmt.Errorf("photo not found") + } + + return photoURL, nil +} + +func (p *Provider) GetFileName(src string) string { + parts := strings.Split(src, "/") + + return parts[len(parts)-1] +} + +func (p *Provider) GetPhotos() ([]string, error) { + albumURL, err := url.JoinPath(p.BaseURL, "a", p.Album) + if err != nil { + return []string{}, err + } + + _, err = p.GetRecentPhotoID() + if err != nil { + return []string{}, err + } + + photos := make([]string, 0) + + c := colly.NewCollector() + + c.OnHTML(".grid-images_box-link", func(e *colly.HTMLElement) { + photos = append(photos, getPhotoID(e.Attr("href"))) + }) + + c.Visit(albumURL) + + if len(photos) == 0 { + return []string{}, fmt.Errorf("photos not found") + } + + return photos, nil +} + +func (p *Provider) GetRecentPhotoID() (string, error) { + c := colly.NewCollector() + + albumURL, err := url.JoinPath(p.BaseURL, "a", p.Album) + if err != nil { + return "", err + } + + recentPhotoID := "" + isFound := false + + c.OnHTML(".grid-images_box-link", func(e *colly.HTMLElement) { + if !isFound { + href := e.Attr("href") + recentPhotoID = getPhotoID(href) + } + }) + + c.Visit(albumURL) + + if recentPhotoID == "" { + return "", fmt.Errorf("album not found") + } + + return recentPhotoID, nil +} + +func getPhotoID(src string) string { + u, err := url.Parse(src) + if err != nil { + return "" + } + + pathParts := strings.Split(u.Path, "/") + + id := pathParts[len(pathParts)-1] + + return id + +} diff --git a/pkg/providers/fapello/fapello.go b/pkg/providers/fapello/fapello.go index ed9f2cd..dafa086 100644 --- a/pkg/providers/fapello/fapello.go +++ b/pkg/providers/fapello/fapello.go @@ -45,8 +45,10 @@ func (p *Provider) GetPhotos() ([]string, error) { return []string{}, err } - if p.MaxPhotoID > recentPhotoID { - p.MaxPhotoID = recentPhotoID + intRecentPhotoID, _ := strconv.Atoi(recentPhotoID) + + if p.MaxPhotoID > intRecentPhotoID { + p.MaxPhotoID = intRecentPhotoID } photos := make([]string, p.MaxPhotoID-p.MinPhotoID+1) @@ -86,12 +88,12 @@ func (p *Provider) GetFileName(url string) string { return parts[len(parts)-1] } -func (p *Provider) GetRecentPhotoID() (int, error) { +func (p *Provider) GetRecentPhotoID() (string, error) { c := colly.NewCollector() userSrc, err := url.JoinPath(p.BaseURL, p.Username) if err != nil { - return 0, err + return "", err } isFound := false @@ -114,10 +116,10 @@ func (p *Provider) GetRecentPhotoID() (int, error) { c.Visit(userSrc) if !isFound { - return 0, fmt.Errorf("user not found") + return "", fmt.Errorf("user not found") } - return recentPhotoID, nil + return strconv.Itoa(recentPhotoID), nil } func buildURL(baseURL string, username string, recentID int) (string, error) { diff --git a/pkg/providers/fapodrop/fapodrop.go b/pkg/providers/fapodrop/fapodrop.go index c68e8bf..1a2feae 100644 --- a/pkg/providers/fapodrop/fapodrop.go +++ b/pkg/providers/fapodrop/fapodrop.go @@ -41,8 +41,10 @@ func (p *Provider) GetPhotos() ([]string, error) { return []string{}, err } - if p.MaxPhotoID > recentPhotoID { - p.MaxPhotoID = recentPhotoID + intRecentPhotoID, _ := strconv.Atoi(recentPhotoID) + + if p.MaxPhotoID > intRecentPhotoID { + p.MaxPhotoID = intRecentPhotoID } photos := make([]string, p.MaxPhotoID-p.MinPhotoID+1) @@ -88,12 +90,12 @@ func buildURL(baseURL string, name string) (string, error) { return photoURL, nil } -func (p *Provider) GetRecentPhotoID() (int, error) { +func (p *Provider) GetRecentPhotoID() (string, error) { c := colly.NewCollector() userSrc, err := url.JoinPath(p.BaseURL, p.Username) if err != nil { - return 0, err + return "", err } isFound := false @@ -115,7 +117,7 @@ func (p *Provider) GetRecentPhotoID() (int, error) { c.Visit(userSrc) - return recentPhotoID, nil + return strconv.Itoa(recentPhotoID), nil } func (p *Provider) GetFileName(url string) string {