From 65bb5732cac5dd140aa1c1bdcbccbe6da9e9b7d1 Mon Sep 17 00:00:00 2001 From: Tigor Hutasuhut Date: Wed, 1 May 2024 00:02:30 +0700 Subject: [PATCH] reddit: fix image copy for existing should go to temp dir first --- api/download_subreddit_images.go | 58 ++++++++++++++++++----- rest/subreddits/create.http | 2 +- rest/subreddits/start.http | 2 +- views/homeview/homeview.templ | 7 ++- views/homeview/recently_added_image.templ | 28 +++++------ 5 files changed, 66 insertions(+), 31 deletions(-) diff --git a/api/download_subreddit_images.go b/api/download_subreddit_images.go index 955e04a..d16176e 100644 --- a/api/download_subreddit_images.go +++ b/api/download_subreddit_images.go @@ -5,10 +5,12 @@ import ( "errors" "image/jpeg" "io" + "io/fs" "net/http" "net/url" "os" "path" + "path/filepath" "strings" "sync" "time" @@ -185,21 +187,32 @@ func (api *API) downloadSubredditImage(ctx context.Context, post reddit.Post, su return api.saveImageToFSAndDatabase(ctx, tmpImageFile, subreddit, post, devices) } +type stat interface { + Stat() (fs.FileInfo, error) +} + func (api *API) saveImageToFSAndDatabase(ctx context.Context, image io.ReadCloser, subreddit *models.Subreddit, post reddit.Post, devices models.DeviceSlice) (err error) { ctx, span := tracer.Start(ctx, "*API.saveImageToFSAndDatabase") defer span.End() defer image.Close() w, close, err := api.createDeviceImageWriters(post, devices) + defer close() if err != nil { return errs.Wrapw(err, "failed to create image files") } log.New(ctx).Debug("saving image files", "post_id", post.GetID(), "post_url", post.GetImageURL(), "devices", devices) - defer close() - _, err = io.Copy(w, image) + size, err := io.Copy(w, image) if err != nil { return errs.Wrapw(err, "failed to save image files") } + if size == 0 { + if s, ok := image.(stat); ok { + if fi, err := s.Stat(); err == nil { + size = fi.Size() + } + } + } var many []*models.ImageSetter now := time.Now() @@ -209,10 +222,6 @@ func (api *API) saveImageToFSAndDatabase(ctx context.Context, image io.ReadClose nsfw = 1 } width, height := post.GetImageSize() - var size int64 - if fi, err := os.Stat(post.GetImageTargetPath(api.config, device)); err == nil { - size = fi.Size() - } many = append(many, &models.ImageSetter{ Subreddit: omit.From(subreddit.Name), @@ -300,14 +309,14 @@ func (api *API) isImageEntryExists(ctx context.Context, post reddit.Post, device ctx, span := tracer.Start(ctx, "*API.IsImageExists") defer span.End() - _, errQuery := models.Images.Query(ctx, api.db, + exist, errQuery := models.Images.Query(ctx, api.db, models.SelectWhere.Images.Device.EQ(device.Slug), models.SelectWhere.Images.PostName.EQ(post.GetName()), - ).One() + ).Exists() _, errStat := os.Stat(post.GetImageTargetPath(api.config, device)) - return errQuery == nil && errStat == nil + return exist && errQuery == nil && errStat == nil } // findImageFileForDevice finds if any of the image file exists for given devices. @@ -317,16 +326,39 @@ func (api *API) isImageEntryExists(ctx context.Context, post reddit.Post, device // Return nil if no image file exists for the devices. // // Ensure to close the file after use. -func (api *API) findImageFileForDevices(ctx context.Context, post reddit.Post, devices models.DeviceSlice) (file *os.File) { +func (api *API) findImageFileForDevices(ctx context.Context, post reddit.Post, devices models.DeviceSlice) (oldImageFile *os.File) { for _, device := range devices { - _, err := os.Stat(post.GetImageTargetPath(api.config, device)) + stat, err := os.Stat(post.GetImageTargetPath(api.config, device)) if err == nil { - file, err = os.Open(post.GetImageTargetPath(api.config, device)) + oldImageFile, err = os.Open(post.GetImageTargetPath(api.config, device)) if err != nil { log.New(ctx).Err(err).Error("failed to open image file", "filename", post.GetImageTargetPath(api.config, device)) return nil } - return file + defer oldImageFile.Close() + + tempFilename := filepath.Join(os.TempDir(), "redmage", stat.Name()) + + tempFileWrite, err := os.Create(tempFilename) + if err != nil { + log.New(ctx).Err(err).Error("failed to create temp file", "filename", post.GetImageTargetPath(api.config, device)) + return nil + } + defer tempFileWrite.Close() + + _, err = io.Copy(tempFileWrite, oldImageFile) + if err != nil { + log.New(ctx).Err(err).Error("failed to copy image file", "filename", post.GetImageTargetPath(api.config, device)) + return nil + } + + rf, err := os.Open(tempFilename) + if err != nil { + log.New(ctx).Err(err).Error("failed to open temp file", "filename", tempFileWrite.Name()) + return nil + } + + return rf } } diff --git a/rest/subreddits/create.http b/rest/subreddits/create.http index 1297c29..d22a461 100644 --- a/rest/subreddits/create.http +++ b/rest/subreddits/create.http @@ -2,7 +2,7 @@ POST http://localhost:8080/api/v1/subreddits HTTP/1.1 Host: localhost:8080 { - "name": "wallpapers", + "name": "wallpaper", "enable_schedule": 1, "schedule": "@daily", "countback": 300 diff --git a/rest/subreddits/start.http b/rest/subreddits/start.http index 95f0c2b..b0b80f2 100644 --- a/rest/subreddits/start.http +++ b/rest/subreddits/start.http @@ -3,5 +3,5 @@ Host: localhost:8080 Content-Type: application/json { - "subreddit": "wallpapers" + "subreddit": "wallpaper" } diff --git a/views/homeview/homeview.templ b/views/homeview/homeview.templ index 679c238..d4413b5 100644 --- a/views/homeview/homeview.templ +++ b/views/homeview/homeview.templ @@ -39,8 +39,7 @@ templ HomeContent(c *views.Context, data Data) { hx-push-url="true" >

- Recently Added - - { strconv.FormatInt(data.TotalImages, 10) } Images + Recently Added

@recentRangeInput(c) @nsfwToggle(c, data) @@ -48,6 +47,10 @@ templ HomeContent(c *views.Context, data Data) {
if data.TotalImages == 0 {

There are no recently added images in the current time range.

+ } else { +

+ Added Images: { strconv.FormatInt(data.TotalImages, 10) } +

} for _, recently := range data.RecentlyAddedImages {
diff --git a/views/homeview/recently_added_image.templ b/views/homeview/recently_added_image.templ index 87e99bc..9b85e76 100644 --- a/views/homeview/recently_added_image.templ +++ b/views/homeview/recently_added_image.templ @@ -1,9 +1,10 @@ package homeview import "github.com/tigorlazuardi/redmage/models" -import "github.com/tigorlazuardi/redmage/api/reddit" import "fmt" import "github.com/tigorlazuardi/redmage/views/utils" +import "strconv" +import "github.com/alecthomas/units" type ImageCardOption uint @@ -19,14 +20,14 @@ const ( ) templ RecentlyAddedImageCard(data *models.Image, opts ImageCardOption) { -
+
{ @@ -40,18 +41,17 @@ templ RecentlyAddedImageCard(data *models.Image, opts ImageCardOption) { >{ truncateTitle(data.PostTitle) } } { data.PostAuthor } -
- @utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt) +
+
+ @utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt, "text-sm")
-
- if data.R.Subreddit != nil { - if !opts.Has(HideSubreddit) { - { data.R.Subreddit.Name } - } - } +
+

Width

+

{ strconv.Itoa(int(data.ImageWidth)) } px

+

Height

+

{ strconv.Itoa(int(data.ImageHeight)) } px

+

Size

+

{ units.MetricBytes(data.ImageSize).Round(1).String() }