package structs import ( "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" "tea.chunkbyte.com/kato/grabrr/lib/constants" "tea.chunkbyte.com/kato/grabrr/lib/helper" ) // AlbumStatsResponse represents the JSON response from the Bunkr API. type AlbumStatsResponse struct { Slug string `json:"slug"` ViewCount int `json:"viewCount"` } // Album represents a Bunkkr album. type Album struct { Title string `json:"title"` Views int `json:"views"` Files []File `json:"files"` ID string `json:"id"` URL *url.URL `json:"url"` SizeKB int64 `json:"size_kb"` } // File represents a single file within a Bunkkr album. type File struct { Title string `json:"title"` SizeKB int64 `json:"size_kb"` DateUploaded time.Time `json:"date_uploaded"` URL *url.URL `json:"url"` Filename string `json:"filename"` Format string `json:"format"` } func (a *Album) GetSize() string { albumSize, err := helper.FormatSizeFromKB(a.SizeKB) if err != nil { fmt.Printf("error: There has been an error parsing the size, defaulting to variable value [%v]", err) albumSize = fmt.Sprintf("Unknown Size (%v Kb)", a.SizeKB) } return albumSize } func (f *File) GetSize() string { fileSize, err := helper.FormatSizeFromKB(f.SizeKB) if err != nil { fmt.Printf("error: There has been an error parsing the size, defaulting to variable value [%v]", err) fileSize = fmt.Sprintf("Unknown Size (%v Kb)", f.SizeKB) } return fileSize } // FUNCTIONS func (album *Album) FetchAlbumViews() (int, error) { url := fmt.Sprintf("https://%s/api/album/stats/%s", constants.MAIN_HOST_URL, album.ID) req, err := http.NewRequest("GET", url, nil) if err != nil { return -1, fmt.Errorf("error creating request: %w", err) } // ✅ https://s.bunkr.ru/api/album/stats/p2WBVS3a // 🔴 https://bunkr.cr/api/album/stats/p2WBVS3a req.Header.Add("Accept-Language", "en-US,en;q=0.6") req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36") client := &http.Client{} resp, err := client.Do(req) if err != nil { return -1, fmt.Errorf("error making request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return -1, fmt.Errorf("request failed with status code: %d", resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { return -1, fmt.Errorf("error reading response body: %w", err) } var albumStats AlbumStatsResponse err = json.Unmarshal(body, &albumStats) if err != nil { return -1, fmt.Errorf("error unmarshaling JSON: %w", err) } return albumStats.ViewCount, nil } func (a *Album) GetKbSize() int64 { var albumSize int64 = 0 for _, v := range a.Files { albumSize += v.SizeKB } return albumSize } func (a *Album) ToString() string { var builder strings.Builder builder.WriteString("🆔 ID: ") builder.WriteString(a.ID) builder.WriteString("\n") builder.WriteString("📂 Album: ") builder.WriteString(a.Title) builder.WriteString("\n") builder.WriteString("👁️ Views: ") builder.WriteString(fmt.Sprintf("%d", a.Views)) builder.WriteString("\n") builder.WriteString("🌐 URL: ") builder.WriteString(a.URL.String()) builder.WriteString("\n") builder.WriteString("💾 Size: ") builder.WriteString(a.GetSize()) builder.WriteString("\n") builder.WriteString("## File List: ##\n") for _, file := range a.Files { fString := strings.ReplaceAll(file.ToString(), "\n", "\n\t") builder.WriteString("\t") builder.WriteString(fString) builder.WriteString("\n\n") } return builder.String() } func (f *File) ToString() string { var builder strings.Builder builder.WriteString("📄 Title: ") builder.WriteString(f.Title) builder.WriteString("\n") builder.WriteString("💾 Size: ") builder.WriteString(f.GetSize()) builder.WriteString("\n") builder.WriteString("📅 Uploaded: ") builder.WriteString(f.DateUploaded.Format(time.RFC3339)) builder.WriteString("\n") builder.WriteString("🌐 URL: ") builder.WriteString(f.URL.String()) builder.WriteString("\n") builder.WriteString("🔘 filename: ") builder.WriteString(f.Filename) builder.WriteString("\n") builder.WriteString("🟫 format: ") builder.WriteString(f.Format) return builder.String() }