mirror of https://github.com/stashapp/stash.git
Improved gallery cover lookup (#3391)
* 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
This commit is contained in:
parent
8b6f7db4ef
commit
2d528733ff
|
@ -31,6 +31,7 @@ fragment ConfigGeneralData on ConfigGeneralResult {
|
|||
logLevel
|
||||
logAccess
|
||||
createGalleriesFromFolders
|
||||
galleryCoverRegex
|
||||
videoExtensions
|
||||
imageExtensions
|
||||
galleryExtensions
|
||||
|
|
|
@ -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"""
|
||||
|
@ -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"""
|
||||
|
|
|
@ -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"
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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 |
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue