reddit: fix image copy for existing should go to temp dir first
This commit is contained in:
parent
c5c8058376
commit
65bb5732ca
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,5 +3,5 @@ Host: localhost:8080
|
|||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"subreddit": "wallpapers"
|
||||
"subreddit": "wallpaper"
|
||||
}
|
||||
|
|
|
@ -39,8 +39,7 @@ templ HomeContent(c *views.Context, data Data) {
|
|||
hx-push-url="true"
|
||||
>
|
||||
<h1 class="mb-4">
|
||||
Recently Added -
|
||||
{ strconv.FormatInt(data.TotalImages, 10) } Images
|
||||
Recently Added
|
||||
</h1>
|
||||
@recentRangeInput(c)
|
||||
@nsfwToggle(c, data)
|
||||
|
@ -48,6 +47,10 @@ templ HomeContent(c *views.Context, data Data) {
|
|||
<div id="recently-added-images">
|
||||
if data.TotalImages == 0 {
|
||||
<h2 class="mt-4">There are no recently added images in the current time range.</h2>
|
||||
} else {
|
||||
<h2 class="mt-4">
|
||||
Added Images: { strconv.FormatInt(data.TotalImages, 10) }
|
||||
</h2>
|
||||
}
|
||||
for _, recently := range data.RecentlyAddedImages {
|
||||
<div class="divider"></div>
|
||||
|
|
|
@ -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) {
|
||||
<div class="not-prose card card-bordered bg-base-100 hover:bg-base-200 shadow-xl w-[256px] min-w-[256px] rounded-xl top-0 hover:-top-1 hover:drop-shadow-2xl transition-all">
|
||||
<div class="not-prose card card-bordered bg-base-100 hover:bg-base-200 shadow-xl min-w-[256px] rounded-xl top-0 hover:-top-1 hover:drop-shadow-2xl transition-all">
|
||||
<figure>
|
||||
<a
|
||||
href={ templ.URL(fmt.Sprintf("/img/%s", data.ImageRelativePath)) }
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
class="object-contain w-[256px] h-[256px]"
|
||||
class="object-contain max-w-[256px] max-h-[256px]"
|
||||
src={ fmt.Sprintf("/img/%s", data.ThumbnailRelativePath) }
|
||||
alt={ data.PostTitle }
|
||||
/>
|
||||
|
@ -40,18 +41,17 @@ templ RecentlyAddedImageCard(data *models.Image, opts ImageCardOption) {
|
|||
>{ truncateTitle(data.PostTitle) }</a>
|
||||
}
|
||||
<a class="text-primary underline" href={ templ.URL(data.PostAuthorURL) }>{ data.PostAuthor }</a>
|
||||
<div>
|
||||
@utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt)
|
||||
<div class="flex-1"></div>
|
||||
<div class="flex w-full justify-end">
|
||||
@utils.RelativeTimeNode(fmt.Sprintf("relative-time-%s", data.PostName), data.CreatedAt, "text-sm")
|
||||
</div>
|
||||
<div class="card-actions justify-between">
|
||||
if data.R.Subreddit != nil {
|
||||
if !opts.Has(HideSubreddit) {
|
||||
<a
|
||||
class="badge badge-outline badge-primary"
|
||||
href={ templ.URL(fmt.Sprintf("https://reddit.com/%s/%s", reddit.SubredditType(data.R.Subreddit.Subtype), data.R.Subreddit.Name)) }
|
||||
>{ data.R.Subreddit.Name } </a>
|
||||
}
|
||||
}
|
||||
<div class="grid grid-cols-2 gap-x-4">
|
||||
<p class="text-xs">Width</p>
|
||||
<p class="text-xs text-end">{ strconv.Itoa(int(data.ImageWidth)) } px</p>
|
||||
<p class="text-xs">Height</p>
|
||||
<p class="text-xs text-end">{ strconv.Itoa(int(data.ImageHeight)) } px</p>
|
||||
<p class="text-xs">Size</p>
|
||||
<p class="text-xs text-end">{ units.MetricBytes(data.ImageSize).Round(1).String() }</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue