Skip to content

Commit

Permalink
adding blurred background to video
Browse files Browse the repository at this point in the history
  • Loading branch information
damongolding committed Jan 22, 2025
1 parent 423e40e commit 2eb9655
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 51 deletions.
1 change: 1 addition & 0 deletions frontend/src/css/video.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.frame--video {
position: relative;
display: flex;
justify-content: center;
width: 100%;
Expand Down
19 changes: 19 additions & 0 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"time"

"github.com/damongolding/immich-kiosk/internal/config"
"github.com/damongolding/immich-kiosk/internal/utils"
gocache "github.com/patrickmn/go-cache"
)

Expand Down Expand Up @@ -88,3 +90,20 @@ func Replace(key string, x any) error {
func ReplaceWithExpiration(key string, x any, t time.Duration) error {
return kioskCache.Replace(key, x, t)
}

func AssetToCache[T any](viewDataToAdd T, requestConfig *config.Config, deviceID, url string) {
utils.TrimHistory(&requestConfig.History, 10)

cachedViewData := []T{}

viewCacheKey := ViewCacheKey(url, deviceID)

if data, found := Get(viewCacheKey); found {
cachedViewData = data.([]T)
}

cachedViewData = append(cachedViewData, viewDataToAdd)

Set(viewCacheKey, cachedViewData)

}
37 changes: 14 additions & 23 deletions internal/routes/routes_image_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,26 +209,33 @@ func processVideo(immichImage *immich.ImmichAsset, sourceType kiosk.Source, requ
// We need to see if the video has been downloaded
// if so, return nil
// if it hasn't been downloaded, download it and return a image
//
// if the video is not available, run processAsset again to get a new image

// Video is available
if VideoManager.IsDownloaded(immichImage.ID) {
immichImage.KioskSource = sourceType

return nil, nil
img, err := fetchImagePreview(immichImage, requestID, deviceID, isPrefetch)

return img, err
}

// video is not available, is video downloading?
if !VideoManager.IsDownloading(immichImage.ID) {
go VideoManager.DownloadVideo(*immichImage, requestConfig, deviceID, requestUrl)
}

// if the video is not available, run processAsset again to get a new image
return processAsset(immichImage, []immich.ImmichAssetType{immich.VideoType}, requestConfig, requestID, deviceID, requestUrl, isPrefetch)
}

func processImage(immichImage *immich.ImmichAsset, sourceType kiosk.Source, requestID string, deviceID string, isPrefetch bool) (image.Image, error) {

immichImage.KioskSource = sourceType

return fetchImagePreview(immichImage, requestID, deviceID, isPrefetch)
img, err := fetchImagePreview(immichImage, requestID, deviceID, isPrefetch)

return img, err

}

// imageToBase64 converts image bytes to a base64 string and logs the processing time.
Expand Down Expand Up @@ -340,13 +347,8 @@ func processViewImageData(imageOrientation immich.ImageOrientation, requestConfi
return common.ViewImageData{}, fmt.Errorf("selecting image: %w", err)
}

// Video has been chosen
if img == nil {
return common.ViewImageData{
ImmichAsset: immichImage,
ImageData: "",
ImageBlurData: "",
}, nil
if immichImage.Type == immich.VideoType {
log.Info("Video found", "img", img)
}

if strings.EqualFold(requestConfig.ImageEffect, "smart-zoom") && len(immichImage.People)+len(immichImage.UnassignedFaces) == 0 {
Expand Down Expand Up @@ -391,19 +393,8 @@ func ProcessViewImageDataWithRatio(imageOrientation immich.ImageOrientation, req
}

func assetToCache(viewDataToAdd common.ViewData, requestConfig *config.Config, deviceID string, requestData *common.RouteRequestData, c echo.Context) {
utils.TrimHistory(&requestConfig.History, 10)

cachedViewData := []common.ViewData{}

viewCacheKey := cache.ViewCacheKey(c.Request().URL.String(), deviceID)

if data, found := cache.Get(viewCacheKey); found {
cachedViewData = data.([]common.ViewData)
}

cachedViewData = append(cachedViewData, viewDataToAdd)

cache.Set(viewCacheKey, cachedViewData)
cache.AssetToCache(viewDataToAdd, requestConfig, deviceID, c.Request().URL.String())

go webhooks.Trigger(requestData, KioskVersion, webhooks.PrefetchAsset, viewDataToAdd)
}
Expand Down
7 changes: 4 additions & 3 deletions internal/routes/routes_video.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"
"strings"

"github.com/charmbracelet/log"
"github.com/damongolding/immich-kiosk/internal/config"
"github.com/labstack/echo/v4"
)
Expand Down Expand Up @@ -52,6 +53,7 @@ func NewVideo(baseConfig *config.Config) echo.HandlerFunc {
end = fileSize - 1

if rangeHeader != "" {
log.Info("using rangeHeader")
// Remove "bytes=" prefix
rangeStr := strings.Replace(rangeHeader, "bytes=", "", 1)
// Split the range into start-end
Expand Down Expand Up @@ -98,13 +100,12 @@ func NewVideo(baseConfig *config.Config) echo.HandlerFunc {
c.Response().Header().Set("Content-Length", strconv.FormatInt(chunkSize, 10))
c.Response().Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
c.Response().Header().Set("Accept-Ranges", "bytes")
c.Response().Header().Set("Connection", "keep-alive")
c.Response().Header().Set("Keep-Alive", "timeout=5, max=100")
// c.Response().Header().Set("Connection", "keep-alive")
// c.Response().Header().Set("Keep-Alive", "timeout=5, max=100")

// Create a limited reader for the chunk
chunk := io.LimitReader(video, chunkSize)

// Stream the chunk
return c.Stream(http.StatusPartialContent, vid.ImmichAsset.OriginalMimeType, chunk)
}
}
12 changes: 10 additions & 2 deletions internal/templates/components/video/video.templ
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ import (

templ Video(viewData common.ViewData) {
<div class="frame">
<div class="frame--background">
<img src={ viewData.Images[0].ImageBlurData } alt="Blurred image background"/>
</div>
<div class="frame--video">
<video
muted
autoplay
playsinline
src={ fmt.Sprintf("/video/%s", viewData.Images[0].ImmichAsset.ID) }
></video>
preload="auto"
>
<source
src={ fmt.Sprintf("/video/%s", viewData.Images[0].ImmichAsset.ID) }
type={ viewData.Images[0].ImmichAsset.OriginalMimeType }
/>
</video>
</div>
</div>
@partials.RenderHistory(viewData)
Expand Down
45 changes: 22 additions & 23 deletions internal/video/video.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ import (
)

var (
tmpDirectory string
videoDirectory string
customTempVideoDir = filepath.Join(os.TempDir(), "immich-kiosk", "videos")

requestConfig config.Config
)

type Video struct {
Expand All @@ -50,8 +46,6 @@ func New(ctx context.Context, base config.Config) (*VideoManager, error) {
return nil, err
}

requestConfig = base

v := &VideoManager{}
go v.VideoCleanup(ctx)

Expand Down Expand Up @@ -163,7 +157,7 @@ func (v *VideoManager) GetVideo(id string) (Video, error) {
return Video{}, fmt.Errorf("video not found")
}

func (v *VideoManager) AddVideoToViewCache(id, fileName, filePath string, requestConfig *config.Config, deviceID, requestUrl string, immichAsset immich.ImmichAsset) {
func (v *VideoManager) AddVideoToViewCache(id, fileName, filePath string, requestConfig *config.Config, deviceID, requestUrl string, immichAsset immich.ImmichAsset, imageBlurData string) {
v.mu.Lock()
defer v.mu.Unlock()

Expand All @@ -180,14 +174,15 @@ func (v *VideoManager) AddVideoToViewCache(id, fileName, filePath string, reques
Config: *requestConfig,
Images: []common.ViewImageData{
common.ViewImageData{
ImmichAsset: immichAsset,
ImmichAsset: immichAsset,
ImageBlurData: imageBlurData,
},
},
}

log.Info("Adding video to cache")

ViewDataToCache(viewDataToAdd, requestConfig, deviceID, nil, requestUrl)
cache.AssetToCache(viewDataToAdd, requestConfig, deviceID, requestUrl)
}

func (v *VideoManager) updateLastAccessed(id string) {
Expand Down Expand Up @@ -277,25 +272,29 @@ func (v *VideoManager) DownloadVideo(immichAsset immich.ImmichAsset, requestConf
return
}

v.AddVideoToViewCache(videoID, filename, filePath, &requestConfig, deviceID, requestUrl, immichAsset)

log.Debug("downloaded video", "path", filePath)
}

func ViewDataToCache(viewDataToAdd common.ViewData, requestConfig *config.Config, deviceID string, requestData any, url string) {
utils.TrimHistory(&requestConfig.History, 10)
imgBytes, err := immichAsset.ImagePreview()
if err != nil {
log.Errorf("getting image preview: %w", err)

Check failure on line 277 in internal/video/video.go

View workflow job for this annotation

GitHub Actions / test

github.com/charmbracelet/log.Errorf does not support error-wrapping directive %w
}

cachedViewData := []common.ViewData{}
img, err := utils.BytesToImage(imgBytes)
if err != nil {
log.Errorf("image BytesToImage: %w", err)

Check failure on line 282 in internal/video/video.go

View workflow job for this annotation

GitHub Actions / test

github.com/charmbracelet/log.Errorf does not support error-wrapping directive %w
}

viewCacheKey := cache.ViewCacheKey(url, deviceID)
img = utils.ApplyExifOrientation(img, immichAsset.IsLandscape, immichAsset.ExifInfo.Orientation)

if data, found := cache.Get(viewCacheKey); found {
cachedViewData = data.([]common.ViewData)
img, err = utils.BlurImage(img, false, 0, 0)
if err != nil {
log.Errorf("getting image preview: %w", err)

Check failure on line 289 in internal/video/video.go

View workflow job for this annotation

GitHub Actions / test

github.com/charmbracelet/log.Errorf does not support error-wrapping directive %w
}

cachedViewData = append(cachedViewData, viewDataToAdd)
imageBlurData, err := utils.ImageToBase64(img)
if err != nil {
log.Errorf("converting image to base64: %w", err)

Check failure on line 294 in internal/video/video.go

View workflow job for this annotation

GitHub Actions / test

github.com/charmbracelet/log.Errorf does not support error-wrapping directive %w
}

cache.Set(viewCacheKey, cachedViewData)
v.AddVideoToViewCache(videoID, filename, filePath, &requestConfig, deviceID, requestUrl, immichAsset, imageBlurData)

// go webhooks.Trigger(requestData, KioskVersion, webhooks.PrefetchAsset, viewDataToAdd)
log.Debug("downloaded video", "path", filePath)
}

0 comments on commit 2eb9655

Please sign in to comment.