Skip to content

Commit

Permalink
Merge pull request #10 from SmilyOrg/large-collections
Browse files Browse the repository at this point in the history
Large collections
  • Loading branch information
SmilyOrg authored Jul 15, 2022
2 parents 34f0da4 + ca1d796 commit 5d1183e
Show file tree
Hide file tree
Showing 23 changed files with 2,355 additions and 2,144 deletions.
24 changes: 6 additions & 18 deletions api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -311,25 +311,10 @@ paths:
"404":
$ref: "#/components/responses/FileNotFound"

/files/{id}/image-variants/{size}/{filename}:
/files/{id}/variants/{size}/{filename}:
get:
description: Get an image thumbnail of the specified predefined size and
with an arbitrary filename as part of the URL
tags: ["Files"]
parameters:
- $ref: "#/components/parameters/FileIdPathParam"
- $ref: "#/components/parameters/FilenamePathParam"
- $ref: "#/components/parameters/SizePathParam"
responses:
"200":
$ref: "#/components/responses/FileResponse"
"404":
$ref: "#/components/responses/FileNotFound"

/files/{id}/video-variants/{size}/{filename}:
get:
description: Get a resized video of the specified predefined size and
with an arbitrary filename as part of the URL
description: Get an image or resized video variant/thumbnail of the
specified predefined size and with an arbitrary filename as part of the URL
tags: ["Files"]
parameters:
- $ref: "#/components/parameters/FileIdPathParam"
Expand Down Expand Up @@ -462,6 +447,9 @@ components:
type: integer
minimum: 0
example: 506
loading:
type: boolean
description: True while the scene is loading and the dimensions are not yet known.

Collection:
type: object
Expand Down
190 changes: 99 additions & 91 deletions defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,96 +60,104 @@ media:
# Extensions to use to understand a file to be an image
extensions: [".jpg", ".jpeg", ".png", ".gif"]

# Pre-generated thumbnail configuration, these thumbnails will be used to
# greatly speed up the rendering
thumbnails:

# name: Short thumbnail type name
#
# path: Path template where to find the thumbnail.
# {{.Dir}} is replaced by the parent directory of the original photo
# {{.Filename}} is replaced by the original photo filename
#
# fit: Aspect ratio fit of the thumbnail in case it doesn't match the
# original photo.
#
# INSIDE
# The thumbnail size is the maximum size of each dimension, so in case
# of different aspect ratios, one dimension will always be smaller.
#
# OUTSIDE
# The thumbnail size is the minimum size of each dimension, so in case
# of different aspect ratios, one dimension will always be bigger.
#
# ORIGINAL
# The size of the thumbnail is equal the size of the original. Mostly
# useful for transcoded or differently encoded files.
#
# width
# height: Predefined thumbnail dimensions used to pick the most
# appropriately-sized thumbnail for the zoom level.
#
# extra_cost: Additional weight to add when picking the closest thumbnail.
# Higher number means that other thumbnails will be preferred
# if they exist.

#
# Embedded JPEG thumbnail
#
- name: exif-thumb
exif: ThumbnailImage
fit: INSIDE
width: 120
height: 120
# It's expensive to extract, so this makes it more of a last resort, but
# still a lot better than loading the original photo.
extra_cost: 10

#
# Synology Moments / Photo Station thumbnails
#
- name: S
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_S.jpg"
fit: INSIDE
width: 120
height: 120

- name: SM
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_SM.jpg"
fit: OUTSIDE
width: 240
height: 240

- name: M
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_M.jpg"
fit: OUTSIDE
width: 320
height: 320

- name: B
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_B.jpg"
fit: INSIDE
width: 640
height: 640

- name: XL
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_XL.jpg"
fit: OUTSIDE
width: 1280
height: 1280

videos:
extensions: [".mp4"]
thumbnails:
#
# Synology Moments / Photo Station video variants
#
- name: M
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_FILM_M.mp4"
fit: OUTSIDE
width: 720
height: 720

- name: H264
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_FILM_H264.mp4"
fit: ORIGINAL

# Pre-generated thumbnail configuration, these thumbnails will be used to
# greatly speed up the rendering
thumbnails:

# name: Short thumbnail type name
#
# path: Path template where to find the thumbnail.
# {{.Dir}} is replaced by the parent directory of the original photo
# {{.Filename}} is replaced by the original photo filename
#
# fit: Aspect ratio fit of the thumbnail in case it doesn't match the
# original photo.
#
# INSIDE
# The thumbnail size is the maximum size of each dimension, so in case
# of different aspect ratios, one dimension will always be smaller.
#
# OUTSIDE
# The thumbnail size is the minimum size of each dimension, so in case
# of different aspect ratios, one dimension will always be bigger.
#
# ORIGINAL
# The size of the thumbnail is equal the size of the original. Mostly
# useful for transcoded or differently encoded files.
#
# width
# height: Predefined thumbnail dimensions used to pick the most
# appropriately-sized thumbnail for the zoom level.
#
# extra_cost: Additional weight to add when picking the closest thumbnail.
# Higher number means that other thumbnails will be preferred
# if they exist.

#
# Embedded JPEG thumbnail
#
- name: exif-thumb
exif: ThumbnailImage
extensions: [".jpg", ".jpeg"]
fit: INSIDE
width: 120
height: 120
# It's expensive to extract, so this makes it more of a last resort, but
# still a lot better than loading the original photo.
extra_cost: 10

#
# Synology Moments / Photo Station thumbnails
#
- name: S
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_S.jpg"
extensions: [".jpg", ".jpeg", ".png", ".gif", ".mp4"]
fit: INSIDE
width: 120
height: 120

- name: SM
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_SM.jpg"
extensions: [".jpg", ".jpeg", ".png", ".gif", ".mp4"]
fit: OUTSIDE
width: 240
height: 240

- name: M
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_M.jpg"
extensions: [".jpg", ".jpeg", ".png", ".gif", ".mp4"]
fit: OUTSIDE
width: 320
height: 320

- name: B
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_B.jpg"
extensions: [".jpg", ".jpeg", ".png", ".gif"]
fit: INSIDE
width: 640
height: 640

- name: XL
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_THUMB_XL.jpg"
extensions: [".jpg", ".jpeg", ".png", ".gif", ".mp4"]
fit: OUTSIDE
width: 1280
height: 1280

#
# Synology Moments / Photo Station video variants
#
- name: FM
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_FILM_M.mp4"
extensions: [".mp4"]
fit: OUTSIDE
width: 720
height: 720

- name: H264
path: "{{.Dir}}@eaDir/{{.Filename}}/SYNOPHOTO_FILM_H264.mp4"
extensions: [".mp4"]
fit: ORIGINAL
14 changes: 7 additions & 7 deletions internal/image/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func (source *Database) GetPathFromId(id ImageId) (string, bool) {
FROM infos
JOIN prefix ON path_prefix_id == prefix.id
WHERE infos.rowid == ?;`)
defer stmt.Finalize()
defer stmt.Reset()

stmt.BindInt64(1, (int64)(id))

Expand All @@ -395,7 +395,7 @@ func (source *Database) Get(id ImageId) (InfoResult, bool) {
SELECT width, height, orientation, color, created_at
FROM infos
WHERE rowid == ?;`)
defer stmt.Finalize()
defer stmt.Reset()

stmt.BindInt64(1, (int64)(id))

Expand Down Expand Up @@ -430,7 +430,7 @@ func (source *Database) GetDir(dir string) (InfoResult, bool) {
stmt := conn.Prep(`
SELECT indexed_at FROM dirs
WHERE path = ?;`)
defer stmt.Finalize()
defer stmt.Reset()

stmt.BindText(1, dir)

Expand Down Expand Up @@ -479,7 +479,7 @@ func (source *Database) SetIndexed(dir string) {
}

func (source *Database) List(dirs []string, options ListOptions) <-chan InfoListResult {
out := make(chan InfoListResult, 10000)
out := make(chan InfoListResult, 1000)
go func() {
defer metrics.Elapsed("listing infos sqlite")()

Expand Down Expand Up @@ -523,7 +523,7 @@ func (source *Database) List(dirs []string, options ListOptions) <-chan InfoList

stmt := conn.Prep(sql)
bindIndex := 1
defer stmt.Finalize()
defer stmt.Reset()

for _, dir := range dirs {
stmt.BindText(bindIndex, dir+"%")
Expand Down Expand Up @@ -604,7 +604,7 @@ func (source *Database) ListPaths(dirs []string, limit int) <-chan string {

stmt := conn.Prep(sql)
bindIndex := 1
defer stmt.Finalize()
defer stmt.Reset()

for _, dir := range dirs {
stmt.BindText(bindIndex, dir+"%")
Expand Down Expand Up @@ -665,7 +665,7 @@ func (source *Database) ListIds(dirs []string, limit int) <-chan ImageId {

stmt := conn.Prep(sql)
bindIndex := 1
defer stmt.Finalize()
defer stmt.Reset()

for _, dir := range dirs {
stmt.BindText(bindIndex, dir+"%")
Expand Down
15 changes: 2 additions & 13 deletions internal/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,9 @@ func (source *Source) GetImageOrThumbnail(path string, thumbnail *Thumbnail) (im
return source.imageCache.GetOrLoad(path, thumbnail, source)
}

func (source *Source) GetSmallestThumbnail(path string) string {
for i := range source.Images.Thumbnails {
thumbnail := &source.Images.Thumbnails[i]
thumbnailPath := thumbnail.GetPath(path)
if source.Exists(thumbnailPath) {
return thumbnailPath
}
}
return ""
}

func (source *Source) LoadSmallestImage(path string) (image.Image, error) {
for i := range source.Images.Thumbnails {
thumbnail := &source.Images.Thumbnails[i]
for i := range source.Thumbnails {
thumbnail := &source.Thumbnails[i]
thumbnailPath := thumbnail.GetPath(path)
file, err := os.Open(thumbnailPath)
if err != nil {
Expand Down
32 changes: 25 additions & 7 deletions internal/image/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ type Config struct {
ConcurrentMetaLoads int `json:"concurrent_meta_loads"`
ConcurrentColorLoads int `json:"concurrent_color_loads"`

ListExtensions []string `json:"extensions"`
DateFormats []string `json:"date_formats"`
Images FileConfig `json:"images"`
Videos FileConfig `json:"videos"`
ListExtensions []string `json:"extensions"`
DateFormats []string `json:"date_formats"`
Images FileConfig `json:"images"`
Videos FileConfig `json:"videos"`
Thumbnails []Thumbnail `json:"thumbnails"`

Caches Caches `json:"caches"`
}

type FileConfig struct {
Extensions []string `json:"extensions"`
Thumbnails []Thumbnail `json:"thumbnails"`
Extensions []string `json:"extensions"`
}

type Source struct {
Expand Down Expand Up @@ -161,7 +161,7 @@ func (source *Source) ListInfos(dirs []string, options ListOptions) <-chan Sourc
for i := range dirs {
dirs[i] = filepath.FromSlash(dirs[i])
}
out := make(chan SourcedInfo, 10000)
out := make(chan SourcedInfo, 1000)
go func() {
infos := source.database.List(dirs, options)
for info := range infos {
Expand Down Expand Up @@ -210,3 +210,21 @@ func (source *Source) GetDir(dir string) Info {
result, _ := source.database.GetDir(dir)
return result.Info
}

func (source *Source) GetApplicableThumbnails(path string) []Thumbnail {
thumbs := make([]Thumbnail, 0, len(source.Thumbnails))
pathExt := strings.ToLower(filepath.Ext(path))
for _, t := range source.Thumbnails {
supported := false
for _, ext := range t.Extensions {
if pathExt == ext {
supported = true
break
}
}
if supported {
thumbs = append(thumbs, t)
}
}
return thumbs
}
4 changes: 2 additions & 2 deletions internal/image/thumbnail.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ type Thumbnail struct {
Name string `json:"name"`
PathTemplateRaw string `json:"path"`
PathTemplate *template.Template

Exif string `json:"exif"`
Exif string `json:"exif"`
Extensions []string `json:"extensions"`

SizeTypeRaw string `json:"fit"`
SizeType ThumbnailSizeType
Expand Down
Loading

0 comments on commit 5d1183e

Please sign in to comment.