Skip to content

Commit

Permalink
Improved gallery cover lookup (#3391)
Browse files Browse the repository at this point in the history
* Gallery cover lookup by regex in config.yml
* Added regex validation and an in-app manual entry
* Improved settings description + some translations
* Add changelog entry
  • Loading branch information
Ksrx01 authored Feb 22, 2023
1 parent 8b6f7db commit 2d52873
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 13 deletions.
1 change: 1 addition & 0 deletions graphql/documents/data/config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ fragment ConfigGeneralData on ConfigGeneralResult {
logLevel
logAccess
createGalleriesFromFolders
galleryCoverRegex
videoExtensions
imageExtensions
galleryExtensions
Expand Down
4 changes: 4 additions & 0 deletions graphql/schema/types/config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ input ConfigGeneralInput {
logAccess: Boolean
"""True if galleries should be created from folders with images"""
createGalleriesFromFolders: Boolean
"""Regex used to identify images as gallery covers"""
galleryCoverRegex: String
"""Array of video file extensions"""
videoExtensions: [String!]
"""Array of image file extensions"""
Expand Down Expand Up @@ -210,6 +212,8 @@ type ConfigGeneralResult {
galleryExtensions: [String!]!
"""True if galleries should be created from folders with images"""
createGalleriesFromFolders: Boolean!
"""Regex used to identify images as gallery covers"""
galleryCoverRegex: String!
"""Array of file regexp to exclude from Video Scans"""
excludes: [String!]!
"""Array of file regexp to exclude from Image Scans"""
Expand Down
5 changes: 3 additions & 2 deletions internal/api/resolver_model_gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/stashapp/stash/internal/api/loaders"
"github.com/stashapp/stash/internal/manager/config"

"github.com/stashapp/stash/pkg/file"
"github.com/stashapp/stash/pkg/image"
Expand Down Expand Up @@ -145,8 +146,8 @@ func (r *galleryResolver) Images(ctx context.Context, obj *models.Gallery) (ret

func (r *galleryResolver) Cover(ctx context.Context, obj *models.Gallery) (ret *models.Image, err error) {
if err := r.withReadTxn(ctx, func(ctx context.Context) error {
// find cover.jpg first
ret, err = image.FindGalleryCover(ctx, r.repository.Image, obj.ID)
// Find cover image first
ret, err = image.FindGalleryCover(ctx, r.repository.Image, obj.ID, config.GetInstance().GetGalleryCoverRegex())
return err
}); err != nil {
return nil, err
Expand Down
10 changes: 10 additions & 0 deletions internal/api/resolver_mutation_configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input ConfigGen
c.Set(config.WriteImageThumbnails, *input.WriteImageThumbnails)
}

if input.GalleryCoverRegex != nil {

_, err := regexp.Compile(*input.GalleryCoverRegex)
if err != nil {
return makeConfigGeneralResult(), fmt.Errorf("Gallery cover regex '%v' invalid, '%v'", *input.GalleryCoverRegex, err.Error())
}

c.Set(config.GalleryCoverRegex, *input.GalleryCoverRegex)
}

if input.Username != nil {
c.Set(config.Username, input.Username)
}
Expand Down
1 change: 1 addition & 0 deletions internal/api/resolver_query_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func makeConfigGeneralResult() *ConfigGeneralResult {
MaxTranscodeSize: &maxTranscodeSize,
MaxStreamingTranscodeSize: &maxStreamingTranscodeSize,
WriteImageThumbnails: config.IsWriteImageThumbnails(),
GalleryCoverRegex: config.GetGalleryCoverRegex(),
APIKey: config.GetAPIKey(),
Username: config.GetUsername(),
Password: config.GetPasswordHash(),
Expand Down
19 changes: 19 additions & 0 deletions internal/manager/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ const (
// rather than use the embedded UI.
CustomUILocation = "custom_ui_location"

// Gallery Cover Regex
GalleryCoverRegex = "gallery_cover_regex"
galleryCoverRegexDefault = `(poster|cover|folder|board)\.[^\.]+$`

// Interface options
MenuItems = "menu_items"

Expand Down Expand Up @@ -642,6 +646,18 @@ func (i *Instance) GetVideoFileNamingAlgorithm() models.HashAlgorithm {
return models.HashAlgorithm(ret)
}

func (i *Instance) GetGalleryCoverRegex() string {
var regexString = i.getString(GalleryCoverRegex)

_, err := regexp.Compile(regexString)
if err != nil {
logger.Warnf("Gallery cover regex '%v' invalid, reverting to default.", regexString)
return galleryCoverRegexDefault
}

return regexString
}

func (i *Instance) GetScrapersPath() string {
return i.getString(ScrapersPath)
}
Expand Down Expand Up @@ -1468,6 +1484,9 @@ func (i *Instance) setDefaultValues(write bool) error {
i.main.SetDefault(ScrapersPath, defaultScrapersPath)
i.main.SetDefault(PluginsPath, defaultPluginsPath)

// Set default gallery cover regex
i.main.SetDefault(GalleryCoverRegex, galleryCoverRegexDefault)

// Set NoProxy default
i.main.SetDefault(NoProxy, noProxyDefault)

Expand Down
17 changes: 6 additions & 11 deletions pkg/image/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import (
"github.com/stashapp/stash/pkg/models"
)

const (
coverFilename = "cover.jpg"
coverFilenameSearchString = "%" + coverFilename
)

type Queryer interface {
Query(ctx context.Context, options models.ImageQueryOptions) (*models.ImageQueryResult, error)
}
Expand Down Expand Up @@ -102,9 +97,9 @@ func FindByGalleryID(ctx context.Context, r Queryer, galleryID int, sortBy strin
}, &findFilter)
}

func FindGalleryCover(ctx context.Context, r Queryer, galleryID int) (*models.Image, error) {
func FindGalleryCover(ctx context.Context, r Queryer, galleryID int, galleryCoverRegex string) (*models.Image, error) {
const useCoverJpg = true
img, err := findGalleryCover(ctx, r, galleryID, useCoverJpg)
img, err := findGalleryCover(ctx, r, galleryID, useCoverJpg, galleryCoverRegex)
if err != nil {
return nil, err
}
Expand All @@ -114,10 +109,10 @@ func FindGalleryCover(ctx context.Context, r Queryer, galleryID int) (*models.Im
}

// return the first image in the gallery
return findGalleryCover(ctx, r, galleryID, !useCoverJpg)
return findGalleryCover(ctx, r, galleryID, !useCoverJpg, galleryCoverRegex)
}

func findGalleryCover(ctx context.Context, r Queryer, galleryID int, useCoverJpg bool) (*models.Image, error) {
func findGalleryCover(ctx context.Context, r Queryer, galleryID int, useCoverJpg bool, galleryCoverRegex string) (*models.Image, error) {
// try to find cover.jpg in the gallery
perPage := 1
sortBy := "path"
Expand All @@ -138,8 +133,8 @@ func findGalleryCover(ctx context.Context, r Queryer, galleryID int, useCoverJpg

if useCoverJpg {
imageFilter.Path = &models.StringCriterionInput{
Value: coverFilenameSearchString,
Modifier: models.CriterionModifierEquals,
Value: "(?i)" + galleryCoverRegex,
Modifier: models.CriterionModifierMatchesRegex,
}
}

Expand Down
8 changes: 8 additions & 0 deletions ui/v2.5/src/components/Settings/SettingsLibraryPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ export const SettingsLibraryPanel: React.FC = () => {
checked={general.writeImageThumbnails ?? false}
onChange={(v) => saveGeneral({ writeImageThumbnails: v })}
/>

<StringSetting
id="gallery-cover-regex"
headingID="config.general.gallery_cover_regex_label"
subHeadingID="config.general.gallery_cover_regex_desc"
value={general.galleryCoverRegex ?? ""}
onChange={(v) => saveGeneral({ galleryCoverRegex: v })}
/>
</SettingSection>

<SettingSection headingID="config.ui.delete_options.heading">
Expand Down
1 change: 1 addition & 0 deletions ui/v2.5/src/docs/en/Changelog/v0200.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
### ✨ New Features
* Support customising the filename regex used for determining the gallery cover image. ([#3391](https://github.com/stashapp/stash/pull/3391))
* Added tenth-place rating precision option. ([#3343](https://github.com/stashapp/stash/pull/3343))
* Added toggleable favorite button to Performer cards. ([#3369](https://github.com/stashapp/stash/pull/3369))

Expand Down
1 change: 1 addition & 0 deletions ui/v2.5/src/docs/en/Manual/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ These options are typically not exposed in the UI and must be changed manually i
| `custom_ui_location` | The file system folder where the UI files will be served from, instead of using the embedded UI. Empty to disable. Stash must be restarted to take effect. |
| `max_upload_size` | Maximum file upload size for import files. Defaults to 1GB. |
| `theme_color` | Sets the `theme-color` property in the UI. |
| `gallery_cover_regex` | The regex responsible for selecting images as gallery covers |
| `proxy` | The url of a HTTP(S) proxy to be used when stash makes calls to online services Example: https://user:password@my.proxy:8080 |
| `no_proxy` | A list of domains for which the proxy must not be used. Default is all local LAN: localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12 |

Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/src/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@
"chrome_cdp_path_desc": "Dateipfad zur Chrome Executable oder einer externen Adresse (beginnend mit http:// oder https://, bspw. http://localhost:9222/json/version) die auf eine Chrome Instanz zeigt.",
"create_galleries_from_folders_desc": "Wenn ausgewählt, erzeuge Galerien aus Verzeichnissen, welche Bilder enthalten.",
"create_galleries_from_folders_label": "Erzeuge Galerien aus Verzeichnissen mit Bilder darin",
"gallery_cover_regex_desc": "Regulärer Ausdruck, verwendet um ein Bild als Galerietitelbild zu identifiziert",
"gallery_cover_regex_label": "Schema für Galerietitelbilder",
"db_path_head": "Datenbank Pfad",
"directory_locations_to_your_content": "Verzeichnis zu Ihren Inhalten",
"excluded_image_gallery_patterns_desc": "Reguläre Ausdrücke für Dateinamen/Pfade von Bildern/Galerien, welche von Scans ausgeschlossen werden und beim Aufräumen der Datenbank berücksichtigt werden sollen",
Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/src/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@
"chrome_cdp_path_desc": "File path to the Chrome executable, or a remote address (starting with http:// or https://, for example http://localhost:9222/json/version) to a Chrome instance.",
"create_galleries_from_folders_desc": "If true, creates galleries from folders containing images.",
"create_galleries_from_folders_label": "Create galleries from folders containing images",
"gallery_cover_regex_desc": "Regexp used to identify an image as gallery cover",
"gallery_cover_regex_label": "Gallery cover pattern",
"db_path_head": "Database Path",
"directory_locations_to_your_content": "Directory locations to your content",
"excluded_image_gallery_patterns_desc": "Regexps of image and gallery files/paths to exclude from Scan and add to Clean",
Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/src/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@
"chrome_cdp_path_desc": "Percorso all'eseguibile di Chrome, o indirizzo remoto (iniziando con http:// o https://, per esempio http://localhost:9222/json/version) verso un'istanza Chrome.",
"create_galleries_from_folders_desc": "Se spuntato, crea gallerie dalle cartelle che contengono immagini.",
"create_galleries_from_folders_label": "Crea gallerie dalle cartelle con immagini",
"gallery_cover_regex_desc": "Espressione regolare usata per identificare un immagine come copertina di galleria",
"gallery_cover_regex_label": "Schema copertina di galleria",
"db_path_head": "Percorso del Database",
"directory_locations_to_your_content": "Percorso della Cartella del tuo contenuto",
"excluded_image_gallery_patterns_desc": "Espressioni Regolari di file/percorsi di immagini e gallerie per escluderle dalla Scansione e aggiungerle alla Pulizia",
Expand Down

0 comments on commit 2d52873

Please sign in to comment.