2024-04-10 17:13:07 +07:00
|
|
|
package reddit
|
|
|
|
|
2024-04-14 00:32:55 +07:00
|
|
|
import (
|
|
|
|
"fmt"
|
2024-04-29 09:52:30 +07:00
|
|
|
"html"
|
2024-04-14 00:32:55 +07:00
|
|
|
"net/url"
|
|
|
|
"path"
|
2024-04-26 22:13:04 +07:00
|
|
|
"path/filepath"
|
2024-04-14 00:32:55 +07:00
|
|
|
"strings"
|
2024-04-27 15:16:14 +07:00
|
|
|
"time"
|
2024-04-14 00:32:55 +07:00
|
|
|
|
|
|
|
"github.com/tigorlazuardi/redmage/config"
|
2024-04-25 12:31:20 +07:00
|
|
|
"github.com/tigorlazuardi/redmage/models"
|
2024-04-14 00:32:55 +07:00
|
|
|
)
|
|
|
|
|
2024-04-10 22:38:19 +07:00
|
|
|
type Listing struct {
|
2024-04-10 17:13:07 +07:00
|
|
|
Kind string `json:"kind"`
|
|
|
|
Data Data `json:"data"`
|
|
|
|
}
|
|
|
|
|
2024-04-10 22:38:19 +07:00
|
|
|
func (l *Listing) GetPosts() []Post {
|
|
|
|
return l.Data.Children
|
|
|
|
}
|
|
|
|
|
2024-04-26 10:51:09 +07:00
|
|
|
func (l *Listing) GetSubreddit() string {
|
|
|
|
length := len(l.Data.Children)
|
|
|
|
if length == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return l.Data.Children[length-1].Data.Subreddit
|
|
|
|
}
|
|
|
|
|
2024-04-25 12:31:20 +07:00
|
|
|
// GetLastAfter returns the last post namee for pagination.
|
|
|
|
//
|
|
|
|
// Returns empty string if there is no more posts to look up.
|
|
|
|
func (l *Listing) GetLastAfter() string {
|
|
|
|
posts := l.GetPosts()
|
|
|
|
if len(posts) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return posts[len(posts)-1].GetName()
|
|
|
|
}
|
|
|
|
|
2024-04-10 17:13:07 +07:00
|
|
|
type (
|
|
|
|
MediaEmbed struct{}
|
|
|
|
SecureMediaEmbed struct{}
|
|
|
|
Gildings struct{}
|
|
|
|
Source struct {
|
|
|
|
URL string `json:"url"`
|
2024-04-14 00:32:55 +07:00
|
|
|
Width int64 `json:"width"`
|
|
|
|
Height int64 `json:"height"`
|
2024-04-10 17:13:07 +07:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
type Resolutions struct {
|
|
|
|
URL string `json:"url"`
|
|
|
|
Width int `json:"width"`
|
|
|
|
Height int `json:"height"`
|
|
|
|
}
|
|
|
|
type (
|
|
|
|
Variants struct{}
|
|
|
|
Images struct {
|
|
|
|
Source Source `json:"source"`
|
|
|
|
Resolutions []Resolutions `json:"resolutions"`
|
|
|
|
Variants Variants `json:"variants"`
|
|
|
|
ID string `json:"id"`
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
type Preview struct {
|
|
|
|
Images []Images `json:"images"`
|
|
|
|
Enabled bool `json:"enabled"`
|
|
|
|
}
|
|
|
|
type LinkFlairRichtext struct {
|
|
|
|
E string `json:"e"`
|
|
|
|
T string `json:"t"`
|
|
|
|
}
|
|
|
|
type ThumbnailPreview struct {
|
|
|
|
Y int `json:"y"`
|
|
|
|
X int `json:"x"`
|
|
|
|
U string `json:"u"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type MediaMetadata struct {
|
|
|
|
Status string `json:"status"`
|
|
|
|
Kind string `json:"e"`
|
|
|
|
Mimetype string `json:"m"`
|
|
|
|
ExtraThumbnails []ThumbnailPreview `json:"p"`
|
|
|
|
Thumbnail ThumbnailPreview `json:"s"`
|
|
|
|
ID string `json:"id"`
|
|
|
|
}
|
|
|
|
type Items struct {
|
|
|
|
OutboundURL string `json:"outbound_url,omitempty"`
|
|
|
|
MediaID string `json:"media_id"`
|
|
|
|
ID int `json:"id"`
|
|
|
|
}
|
|
|
|
type GalleryData struct {
|
|
|
|
Items []Items `json:"items"`
|
|
|
|
}
|
|
|
|
type AuthorFlairRichtext struct {
|
|
|
|
E string `json:"e"`
|
|
|
|
T string `json:"t"`
|
|
|
|
}
|
2024-04-10 22:38:19 +07:00
|
|
|
type PostData struct {
|
2024-04-10 17:13:07 +07:00
|
|
|
ApprovedAtUtc any `json:"approved_at_utc"`
|
|
|
|
Subreddit string `json:"subreddit"`
|
|
|
|
Selftext string `json:"selftext"`
|
|
|
|
AuthorFullname string `json:"author_fullname"`
|
|
|
|
Saved bool `json:"saved"`
|
|
|
|
ModReasonTitle any `json:"mod_reason_title"`
|
|
|
|
Gilded int `json:"gilded"`
|
|
|
|
Clicked bool `json:"clicked"`
|
|
|
|
IsGallery bool `json:"is_gallery"`
|
|
|
|
Title string `json:"title"`
|
|
|
|
LinkFlairRichtext []LinkFlairRichtext `json:"link_flair_richtext"`
|
|
|
|
SubredditNamePrefixed string `json:"subreddit_name_prefixed"`
|
|
|
|
Hidden bool `json:"hidden"`
|
|
|
|
Pwls int `json:"pwls"`
|
|
|
|
LinkFlairCSSClass string `json:"link_flair_css_class"`
|
|
|
|
Downs int `json:"downs"`
|
2024-04-14 00:32:55 +07:00
|
|
|
ThumbnailHeight int64 `json:"thumbnail_height"`
|
2024-04-10 17:13:07 +07:00
|
|
|
TopAwardedType any `json:"top_awarded_type"`
|
|
|
|
HideScore bool `json:"hide_score"`
|
|
|
|
MediaMetadata map[string]MediaMetadata `json:"media_metadata"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Quarantine bool `json:"quarantine"`
|
|
|
|
LinkFlairTextColor any `json:"link_flair_text_color"`
|
|
|
|
UpvoteRatio float64 `json:"upvote_ratio"`
|
|
|
|
AuthorFlairBackgroundColor any `json:"author_flair_background_color"`
|
|
|
|
Ups int `json:"ups"`
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
MediaEmbed MediaEmbed `json:"media_embed"`
|
2024-04-14 00:32:55 +07:00
|
|
|
ThumbnailWidth int64 `json:"thumbnail_width"`
|
2024-04-10 17:13:07 +07:00
|
|
|
AuthorFlairTemplateID string `json:"author_flair_template_id"`
|
|
|
|
IsOriginalContent bool `json:"is_original_content"`
|
|
|
|
UserReports []any `json:"user_reports"`
|
|
|
|
SecureMedia any `json:"secure_media"`
|
|
|
|
IsRedditMediaDomain bool `json:"is_reddit_media_domain"`
|
|
|
|
IsMeta bool `json:"is_meta"`
|
|
|
|
Category any `json:"category"`
|
|
|
|
SecureMediaEmbed SecureMediaEmbed `json:"secure_media_embed"`
|
|
|
|
GalleryData GalleryData `json:"gallery_data"`
|
|
|
|
LinkFlairText string `json:"link_flair_text"`
|
|
|
|
CanModPost bool `json:"can_mod_post"`
|
|
|
|
Score int `json:"score"`
|
|
|
|
ApprovedBy any `json:"approved_by"`
|
|
|
|
IsCreatedFromAdsUI bool `json:"is_created_from_ads_ui"`
|
|
|
|
AuthorPremium bool `json:"author_premium"`
|
|
|
|
Thumbnail string `json:"thumbnail"`
|
2024-04-27 15:16:14 +07:00
|
|
|
Edited any `json:"edited"`
|
2024-04-10 17:13:07 +07:00
|
|
|
AuthorFlairCSSClass string `json:"author_flair_css_class"`
|
|
|
|
AuthorFlairRichtext []AuthorFlairRichtext `json:"author_flair_richtext"`
|
|
|
|
Gildings Gildings `json:"gildings"`
|
|
|
|
ContentCategories any `json:"content_categories"`
|
|
|
|
IsSelf bool `json:"is_self"`
|
|
|
|
SubredditType string `json:"subreddit_type"`
|
2024-04-26 10:51:09 +07:00
|
|
|
Created float64 `json:"created"`
|
2024-04-10 17:13:07 +07:00
|
|
|
LinkFlairType string `json:"link_flair_type"`
|
|
|
|
Wls int `json:"wls"`
|
|
|
|
RemovedByCategory any `json:"removed_by_category"`
|
|
|
|
BannedBy any `json:"banned_by"`
|
|
|
|
AuthorFlairType string `json:"author_flair_type"`
|
|
|
|
TotalAwardsReceived int `json:"total_awards_received"`
|
|
|
|
AllowLiveComments bool `json:"allow_live_comments"`
|
|
|
|
SelftextHTML any `json:"selftext_html"`
|
|
|
|
Likes any `json:"likes"`
|
|
|
|
SuggestedSort any `json:"suggested_sort"`
|
|
|
|
BannedAtUtc any `json:"banned_at_utc"`
|
|
|
|
URLOverriddenByDest string `json:"url_overridden_by_dest"`
|
|
|
|
ViewCount any `json:"view_count"`
|
|
|
|
Archived bool `json:"archived"`
|
|
|
|
NoFollow bool `json:"no_follow"`
|
|
|
|
IsCrosspostable bool `json:"is_crosspostable"`
|
|
|
|
Pinned bool `json:"pinned"`
|
|
|
|
Over18 bool `json:"over_18"`
|
|
|
|
AllAwardings []any `json:"all_awardings"`
|
|
|
|
Awarders []any `json:"awarders"`
|
|
|
|
MediaOnly bool `json:"media_only"`
|
|
|
|
CanGild bool `json:"can_gild"`
|
|
|
|
Spoiler bool `json:"spoiler"`
|
|
|
|
Locked bool `json:"locked"`
|
|
|
|
AuthorFlairText string `json:"author_flair_text"`
|
|
|
|
TreatmentTags []any `json:"treatment_tags"`
|
|
|
|
Visited bool `json:"visited"`
|
|
|
|
RemovedBy any `json:"removed_by"`
|
|
|
|
ModNote any `json:"mod_note"`
|
|
|
|
Distinguished any `json:"distinguished"`
|
|
|
|
SubredditID string `json:"subreddit_id"`
|
|
|
|
AuthorIsBlocked bool `json:"author_is_blocked"`
|
|
|
|
ModReasonBy any `json:"mod_reason_by"`
|
|
|
|
NumReports any `json:"num_reports"`
|
|
|
|
RemovalReason any `json:"removal_reason"`
|
|
|
|
LinkFlairBackgroundColor any `json:"link_flair_background_color"`
|
|
|
|
ID string `json:"id"`
|
|
|
|
IsRobotIndexable bool `json:"is_robot_indexable"`
|
|
|
|
ReportReasons any `json:"report_reasons"`
|
|
|
|
Author string `json:"author"`
|
|
|
|
DiscussionType any `json:"discussion_type"`
|
|
|
|
NumComments int `json:"num_comments"`
|
|
|
|
SendReplies bool `json:"send_replies"`
|
|
|
|
WhitelistStatus string `json:"whitelist_status"`
|
|
|
|
ContestMode bool `json:"contest_mode"`
|
|
|
|
ModReports []any `json:"mod_reports"`
|
|
|
|
AuthorPatreonFlair bool `json:"author_patreon_flair"`
|
|
|
|
AuthorFlairTextColor string `json:"author_flair_text_color"`
|
|
|
|
Permalink string `json:"permalink"`
|
|
|
|
ParentWhitelistStatus string `json:"parent_whitelist_status"`
|
|
|
|
Stickied bool `json:"stickied"`
|
|
|
|
URL string `json:"url"`
|
|
|
|
SubredditSubscribers int `json:"subreddit_subscribers"`
|
2024-04-26 10:51:09 +07:00
|
|
|
CreatedUtc float64 `json:"created_utc"`
|
2024-04-10 17:13:07 +07:00
|
|
|
NumCrossposts int `json:"num_crossposts"`
|
|
|
|
Media any `json:"media"`
|
|
|
|
IsVideo bool `json:"is_video"`
|
2024-04-10 22:38:19 +07:00
|
|
|
PostHint string `json:"post_hint"`
|
|
|
|
Preview Preview `json:"preview"`
|
2024-04-10 17:13:07 +07:00
|
|
|
}
|
2024-04-10 22:38:19 +07:00
|
|
|
|
|
|
|
type Post struct {
|
|
|
|
Kind string `json:"kind"`
|
|
|
|
Data PostData `json:"data,omitempty"`
|
|
|
|
}
|
|
|
|
|
2024-04-14 00:32:55 +07:00
|
|
|
func (post *Post) IsNSFW() bool {
|
|
|
|
return post.Data.Over18
|
|
|
|
}
|
|
|
|
|
2024-06-11 15:13:56 +07:00
|
|
|
func (post *Post) IsNSFWInt() int {
|
|
|
|
if post.IsNSFW() {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2024-04-10 22:38:19 +07:00
|
|
|
func (post *Post) IsImagePost() bool {
|
|
|
|
return post.Data.PostHint == "image"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetImageURL() string {
|
|
|
|
return post.Data.URL
|
2024-04-10 17:13:07 +07:00
|
|
|
}
|
2024-04-10 22:38:19 +07:00
|
|
|
|
2024-04-27 15:16:14 +07:00
|
|
|
func (post *Post) GetCreated() time.Time {
|
|
|
|
return time.Unix(int64(post.Data.Created), 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetAuthor() string {
|
|
|
|
return post.Data.Author
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetTitle() string {
|
2024-04-29 09:52:30 +07:00
|
|
|
return html.UnescapeString(post.Data.Title)
|
2024-04-27 15:16:14 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetAuthorURL() string {
|
|
|
|
return fmt.Sprintf("https://www.reddit.com/user/%s", post.Data.Author)
|
|
|
|
}
|
|
|
|
|
2024-04-14 00:32:55 +07:00
|
|
|
func (post *Post) GetImageAspectRatio() float64 {
|
|
|
|
width, height := post.GetImageSize()
|
|
|
|
if height == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return float64(width) / float64(height)
|
|
|
|
}
|
|
|
|
|
2024-04-25 12:31:20 +07:00
|
|
|
func (post *Post) GetName() string {
|
|
|
|
return post.Data.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetImageTargetPath(cfg *config.Config, device *models.Device) string {
|
2024-05-07 22:50:23 +07:00
|
|
|
if device.WindowsWallpaperMode == 1 {
|
|
|
|
return post.GetWindowsWallpaperImageTargetPath(cfg, device)
|
|
|
|
}
|
2024-04-14 00:32:55 +07:00
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
2024-04-26 22:13:04 +07:00
|
|
|
p := path.Join(baseDownloadDir, device.Slug, post.GetSubreddit(), post.GetImageFilename())
|
|
|
|
abs, _ := filepath.Abs(p)
|
|
|
|
return abs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetImageTargetDir(cfg *config.Config, device *models.Device) string {
|
2024-05-07 22:50:23 +07:00
|
|
|
if device.WindowsWallpaperMode == 1 {
|
|
|
|
return post.GetWindowsWallpaperImageTargetDir(cfg, device)
|
|
|
|
}
|
2024-04-26 22:13:04 +07:00
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
|
|
|
p := path.Join(baseDownloadDir, device.Slug, post.GetSubreddit())
|
|
|
|
abs, _ := filepath.Abs(p)
|
|
|
|
return abs
|
2024-04-14 00:32:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-25 12:31:20 +07:00
|
|
|
func (post *Post) GetWindowsWallpaperImageTargetPath(cfg *config.Config, device *models.Device) string {
|
2024-04-14 00:32:55 +07:00
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
|
|
|
filename := fmt.Sprintf("%s_%s", post.GetSubreddit(), post.GetImageFilename())
|
2024-04-26 22:13:04 +07:00
|
|
|
p := path.Join(baseDownloadDir, device.Slug, filename)
|
|
|
|
abs, _ := filepath.Abs(p)
|
|
|
|
return abs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetWindowsWallpaperImageTargetDir(cfg *config.Config, device *models.Device) string {
|
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
|
|
|
p := path.Join(baseDownloadDir, device.Slug)
|
|
|
|
abs, _ := filepath.Abs(p)
|
|
|
|
return abs
|
2024-04-14 00:32:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetThumbnailTargetPath(cfg *config.Config) string {
|
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
2024-04-26 22:13:04 +07:00
|
|
|
p := path.Join(baseDownloadDir, "_thumbnails", post.GetSubreddit(), post.GetImageFilename())
|
|
|
|
abs, _ := filepath.Abs(p)
|
2024-05-05 23:28:29 +07:00
|
|
|
if before, found := strings.CutSuffix(abs, ".png"); found {
|
|
|
|
return before + ".jpeg"
|
|
|
|
}
|
2024-04-26 22:13:04 +07:00
|
|
|
return abs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetThumbnailTargetDir(cfg *config.Config) string {
|
|
|
|
baseDownloadDir := cfg.String("download.directory")
|
|
|
|
p := path.Join(baseDownloadDir, "_thumbnails", post.GetSubreddit())
|
|
|
|
abs, _ := filepath.Abs(p)
|
|
|
|
return abs
|
2024-04-14 00:32:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-14 13:11:10 +07:00
|
|
|
func (post *Post) GetThumbnailRelativePath() string {
|
2024-05-05 23:28:29 +07:00
|
|
|
p := path.Join("_thumbnails", post.GetSubreddit(), post.GetImageFilename())
|
|
|
|
if before, found := strings.CutSuffix(p, ".png"); found {
|
|
|
|
return before + ".jpeg"
|
|
|
|
}
|
|
|
|
return p
|
2024-04-14 13:11:10 +07:00
|
|
|
}
|
|
|
|
|
2024-04-25 12:31:20 +07:00
|
|
|
func (post *Post) GetImageRelativePath(device *models.Device) string {
|
2024-05-07 22:50:23 +07:00
|
|
|
if device.WindowsWallpaperMode == 1 {
|
|
|
|
return post.GetWindowsWallpaperImageRelativePath(device)
|
|
|
|
}
|
|
|
|
|
2024-04-14 17:30:04 +07:00
|
|
|
return path.Join(device.Slug, post.GetSubreddit(), post.GetImageFilename())
|
2024-04-14 13:11:10 +07:00
|
|
|
}
|
|
|
|
|
2024-04-25 12:31:20 +07:00
|
|
|
func (post *Post) GetWindowsWallpaperImageRelativePath(device *models.Device) string {
|
2024-04-14 13:11:10 +07:00
|
|
|
filename := fmt.Sprintf("%s_%s", post.GetSubreddit(), post.GetImageFilename())
|
2024-04-14 17:30:04 +07:00
|
|
|
return path.Join(device.Slug, filename)
|
2024-04-14 13:11:10 +07:00
|
|
|
}
|
|
|
|
|
2024-04-14 00:32:55 +07:00
|
|
|
func (post *Post) GetImageFilename() string {
|
|
|
|
if !post.IsImagePost() {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
link := post.GetImageURL()
|
|
|
|
u, _ := url.Parse(link)
|
|
|
|
if u == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
split := strings.Split(u.Path, "/")
|
|
|
|
return split[len(split)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetImageSize() (width, height int64) {
|
2024-04-10 22:38:19 +07:00
|
|
|
if len(post.Data.Preview.Images) == 0 {
|
|
|
|
return 0, 0
|
|
|
|
}
|
|
|
|
source := post.Data.Preview.Images[0].Source
|
2024-04-11 16:04:13 +07:00
|
|
|
return source.Width, source.Height
|
2024-04-10 22:38:19 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetThumbnailURL() string {
|
|
|
|
return post.Data.Thumbnail
|
|
|
|
}
|
|
|
|
|
2024-04-14 00:32:55 +07:00
|
|
|
func (post *Post) GetThumbnailSize() (width, height int64) {
|
2024-04-11 16:04:13 +07:00
|
|
|
return post.Data.ThumbnailWidth, post.Data.ThumbnailHeight
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetSubreddit() string {
|
|
|
|
return post.Data.Subreddit
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetPermalink() string {
|
|
|
|
return post.Data.Permalink
|
|
|
|
}
|
|
|
|
|
2024-04-27 15:16:14 +07:00
|
|
|
func (post *Post) GetPostURL() string {
|
2024-04-27 22:07:20 +07:00
|
|
|
return fmt.Sprintf("https://reddit.com%s", post.Data.Permalink)
|
2024-04-27 15:16:14 +07:00
|
|
|
}
|
|
|
|
|
2024-06-11 15:13:56 +07:00
|
|
|
func (post *Post) GetPostName() string {
|
|
|
|
return post.Data.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetPostTitle() string {
|
|
|
|
return post.Data.Title
|
|
|
|
}
|
|
|
|
|
|
|
|
func (post *Post) GetPostCreated() int64 {
|
|
|
|
return int64(post.Data.Created)
|
|
|
|
}
|
|
|
|
|
2024-04-11 16:04:13 +07:00
|
|
|
func (post *Post) GetID() string {
|
|
|
|
return post.Data.ID
|
2024-04-10 22:38:19 +07:00
|
|
|
}
|
|
|
|
|
2024-04-10 17:13:07 +07:00
|
|
|
type Data struct {
|
2024-04-10 22:38:19 +07:00
|
|
|
After string `json:"after"`
|
|
|
|
Dist int `json:"dist"`
|
|
|
|
Modhash string `json:"modhash"`
|
|
|
|
GeoFilter any `json:"geo_filter"`
|
|
|
|
Children []Post `json:"children"`
|
|
|
|
Before any `json:"before"`
|
2024-04-10 17:13:07 +07:00
|
|
|
}
|