Use overlay

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-08-17 21:21:52 +03:00
parent 795ea28583
commit 4330c20faf
95 changed files with 551 additions and 736 deletions

View File

@@ -1,250 +0,0 @@
diff --git a/data/darktableconfig.xml.in b/data/darktableconfig.xml.in
index 4cd5497ab8..227493e754 100644
--- a/data/darktableconfig.xml.in
+++ b/data/darktableconfig.xml.in
@@ -1524,6 +1524,22 @@
<longdescription>file naming pattern used for a import session</longdescription>
</dtconfig>
+ <dtconfig prefs="import" section="session">
+ <name>session/conflict_padding</name>
+ <type>int</type>
+ <default>2</default>
+ <shortdescription>burst file name conflict number padding</shortdescription>
+ <longdescription>set the padding length for conflict resolution (e.g., 001, 002).</longdescription>
+ </dtconfig>
+
+ <dtconfig prefs="import" section="session">
+ <name>session/import_existing_sidecar</name>
+ <type>bool</type>
+ <default>true</default>
+ <shortdescription>import existing sidecar files</shortdescription>
+ <longdescription>import existing sidecar files (XMP, IPTC, etc.) when importing images</longdescription>
+ </dtconfig>
+
<dtconfig>
<name>plugins/lighttable/layout</name>
<type>int</type>
diff --git a/src/common/import_session.c b/src/common/import_session.c
index 03d4212c5b..ed07369b7e 100644
--- a/src/common/import_session.c
+++ b/src/common/import_session.c
@@ -266,44 +266,38 @@ const char *dt_import_session_filename(dt_import_session_t *self, const gboolean
return NULL;
}
+ self->vp->retry_count = 0;
+
/* verify that expanded path and filename yields a unique file */
const char *path = dt_import_session_path(self, TRUE);
if(use_filename)
result_fname = g_strdup(self->vp->filename);
else
- result_fname = _import_session_filename_from_pattern(self, pattern);
-
- char *fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- char *previous_fname = fname;
- if(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE)
{
- dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists", fname);
do
{
- /* file exists, yield a new filename */
+ /* generate filename based on the current retry_count */
g_free(result_fname);
result_fname = _import_session_filename_from_pattern(self, pattern);
- fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- dt_print(DT_DEBUG_ALWAYS, "[import_session] Testing %s", fname);
- /* check if same filename was yielded as before */
- if(strcmp(previous_fname, fname) == 0)
+ char *test_path = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
+
+ if(g_file_test(test_path, G_FILE_TEST_EXISTS) == TRUE)
{
- g_free(previous_fname);
- g_free(fname);
- dt_control_log(_(
- "couldn't expand to a unique filename for session, please check your import session settings"));
- return NULL;
+ dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists, retrying.\n", test_path);
+ self->vp->retry_count++;
+ g_free(test_path);
+ }
+ else
+ {
+ g_free(test_path);
+ break;
}
- g_free(previous_fname);
- previous_fname = fname;
-
- } while(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE);
+ } while(TRUE);
}
- g_free(previous_fname);
g_free(pattern);
self->current_filename = result_fname;
diff --git a/src/common/variables.c b/src/common/variables.c
index beb74b7f1c..23bce605c4 100644
--- a/src/common/variables.c
+++ b/src/common/variables.c
@@ -1000,6 +1000,14 @@ static char *_get_base_value(dt_variables_params_t *params, char **variable)
else if(_has_prefix(variable, "DARKTABLE.NAME")
|| _has_prefix(variable, "DARKTABLE_NAME"))
result = g_strdup(PACKAGE_NAME);
+
+ else if(_has_prefix(variable, "CONFLICT_PADDING"))
+ {
+ int pad_length = dt_conf_get_int("session/conflict_padding");
+ if(pad_length < 0) pad_length = 0;
+ result = g_strdup_printf("%0*u", pad_length, params->retry_count);
+ }
+
else
{
// go past what looks like an invalid variable. we only expect to
diff --git a/src/common/variables.h b/src/common/variables.h
index 86052a9a3d..a5d616a94c 100644
--- a/src/common/variables.h
+++ b/src/common/variables.h
@@ -29,6 +29,9 @@ typedef struct dt_variables_params_t
/** used for expanding variables that uses filename $(FILE_FOLDER) $(FILE_NAME) and $(FILE_EXTENSION). */
const gchar *filename;
+ /** used for conflict resolution in filename expansion */
+ int retry_count;
+
/** used for expanding variable $(JOBCODE) */
const gchar *jobcode;
diff --git a/src/control/jobs/control_jobs.c b/src/control/jobs/control_jobs.c
index 62908d100c..28302da7b7 100644
--- a/src/control/jobs/control_jobs.c
+++ b/src/control/jobs/control_jobs.c
@@ -2664,6 +2664,59 @@ void dt_control_write_sidecar_files()
FALSE));
}
+static gboolean _copy_file(const char *source, const char *destination)
+{
+ gchar *data = NULL;
+ gsize size = 0;
+
+ if(!g_file_get_contents(source, &data, &size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to read file `%s`", source);
+ return FALSE;
+ }
+
+ if(!g_file_set_contents(destination, data, size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file `%s`", destination);
+ g_free(data);
+ return FALSE;
+ }
+
+ g_free(data);
+ return TRUE;
+}
+
+static void _copy_timestamps(const char *source, const char *destination)
+{
+ struct stat statbuf;
+ if(stat(source, &statbuf) == 0)
+ {
+#ifdef _WIN32
+ struct utimbuf times;
+ times.actime = statbuf.st_atime;
+ times.modtime = statbuf.st_mtime;
+ utime(destination, &times);
+#else
+ struct timeval times[2];
+ times[0].tv_sec = statbuf.st_atime;
+ times[1].tv_sec = statbuf.st_mtime;
+#ifdef __APPLE__
+#ifndef _POSIX_SOURCE
+ times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
+#else
+ times[0].tv_usec = statbuf.st_atimensec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimensec * 0.001;
+#endif
+#else
+ times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
+#endif
+ utimes(destination, times);
+#endif
+ }
+}
+
static int _control_import_image_copy(const char *filename,
char **prev_filename,
char **prev_output,
@@ -2707,37 +2760,37 @@ static int _control_import_image_copy(const char *filename,
g_free(basename);
}
- if(!g_file_set_contents(output, data, size, NULL))
+ if(!_copy_file(filename, output))
{
dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file %s", output);
res = FALSE;
}
else
{
-#ifdef _WIN32
- struct utimbuf times;
- times.actime = statbuf.st_atime;
- times.modtime = statbuf.st_mtime;
- utime(output, &times); // set origin file timestamps
-#else
- struct timeval times[2];
- times[0].tv_sec = statbuf.st_atime;
- times[1].tv_sec = statbuf.st_mtime;
-#ifdef __APPLE__
-#ifndef _POSIX_SOURCE
- times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
-#else
- times[0].tv_usec = statbuf.st_atimensec * 0.001;
- times[1].tv_usec = statbuf.st_mtimensec * 0.001;
-#endif
-#else
- times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
-#endif
- utimes(output, times); // set origin file timestamps
-#endif
+ _copy_timestamps(filename, output);
+ }
+ gboolean import_existing_sidecar = dt_conf_get_bool("session/import_existing_sidecar");
+ if(import_existing_sidecar)
+ {
+ char *xml_filename = g_strdup_printf("%s.xmp", filename);
+ if(g_file_test(xml_filename, G_FILE_TEST_EXISTS))
+ {
+ char *xml_output = g_strdup_printf("%s.xmp", output);
+ if(_copy_file(xml_filename, xml_output))
+ _copy_timestamps(xml_filename, xml_output);
+ else
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to copy sidecar %s", xml_filename);
+ res = FALSE;
+ }
+ g_free(xml_output);
+ }
+ g_free(xml_filename);
+ }
+
+ if(res)
+ {
const dt_imgid_t imgid = dt_image_import(dt_import_session_film_id(session),
output, FALSE, FALSE);
if(!dt_is_valid_imgid(imgid)) dt_control_log(_("error loading file `%s'"), output);

View File

@@ -1,24 +1,6 @@
{ user, home }:
{ pkgs, ... }:
{
config,
inputs,
pkgs,
system,
...
}:
let
selfPkgs = inputs.self.packages.${system};
hmConfig = config.home-manager.users.${user};
in
{
nixpkgs.overlays = [
(final: prev: {
darktable = prev.darktable.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./better-copy-and-import.patch ];
});
})
];
environment.persistence = {
"/persist/state" = {
"${home}/.config/darktable/data.db" = { };
@@ -28,21 +10,10 @@ in
};
home-manager.users.${user} = {
home = {
packages =
with pkgs;
with selfPkgs;
[
darktable
exiftool
darktable-ghost-cms-publish
];
sessionVariables = {
GHOST_URL = "https://photos.karaolidis.com";
GHOST_ADMIN_API_KEY_PATH = hmConfig.sops.secrets."jupiter/photos.karaolidis.com/admin".path;
};
};
home.packages = with pkgs; [
darktable
exiftool
];
xdg.configFile = {
"darktable/darktablerc".source = (pkgs.formats.keyValue { }).generate "darktablerc" {
@@ -69,19 +40,13 @@ in
"darktable/luarc".text = ''
require "tools/script_manager"
require "tools/publish"
'';
"darktable/lua/lib".source = "${selfPkgs.darktable-lua-scripts}/lib";
"darktable/lua/lib".source = "${pkgs.darktable-lua-scripts}/lib";
"darktable/lua/tools/script_manager.lua".source =
"${selfPkgs.darktable-lua-scripts}/tools/script_manager.lua";
"darktable/lua/tools/publish.lua".source =
"${selfPkgs.darktable-ghost-cms-publish}/lib/darktable-ghost-cms-publish/publish.lua";
"${pkgs.darktable-lua-scripts}/tools/script_manager.lua";
"darktable/luts".source = selfPkgs.darktable-hald-clut;
"darktable/luts".source = pkgs.darktable-hald-clut;
};
sops.secrets."jupiter/photos.karaolidis.com/admin".sopsFile =
"${inputs.secrets}/domains/personal/secrets.yaml";
};
}

View File

@@ -6,14 +6,6 @@
...
}:
{
nixpkgs.overlays = [
(final: prev: {
hyprland = prev.hyprland.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./fix-maxwidth-resolution-mode.patch ];
});
})
];
programs.hyprland = {
enable = true;
withUWSM = true;

View File

@@ -1,13 +0,0 @@
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 635c7977..80093c0d 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -2091,6 +2091,8 @@ bool CMonitorRuleParser::parseMode(const std::string& value) {
m_rule.resolution = Vector2D(-1, -1);
else if (value.starts_with("highres"))
m_rule.resolution = Vector2D(-1, -2);
+ else if (value.starts_with("maxwidth"))
+ m_rule.resolution = Vector2D(-1, -3);
else if (parseModeLine(value, m_rule.drmMode)) {
m_rule.resolution = Vector2D(m_rule.drmMode.hdisplay, m_rule.drmMode.vdisplay);
m_rule.refreshRate = float(m_rule.drmMode.vrefresh) / 1000;

View File

@@ -1,12 +1,6 @@
{ user, home }:
{ pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
mpv = pkgs.mpv-unwrapped.wrapper { mpv = pkgs.mpv-unwrapped.override { cddaSupport = true; }; };
})
];
home-manager.users.${user} = {
programs.mpv = {
enable = true;

View File

@@ -4,11 +4,9 @@
lib,
pkgs,
inputs,
system,
...
}:
let
selfPkgs = inputs.self.packages.${system};
hmConfig = config.home-manager.users.${user};
in
{
@@ -78,9 +76,9 @@ in
}
];
communityPlugins = [
communityPlugins = with pkgs; [
{
pkg = selfPkgs.obsidian-plugin-better-word-count;
pkg = obsidianPlugins.better-word-count;
settings = {
statusBar = [
{
@@ -106,7 +104,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-dataview;
pkg = obsidianPlugins.dataview;
settings = {
enableDataviewJs = true;
enableInlineDataviewJs = true;
@@ -116,7 +114,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-excalidraw;
pkg = obsidianPlugins.excalidraw;
settings = {
folder = "Inbox";
templateFilePath = "Templates";
@@ -139,7 +137,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-kanban;
pkg = obsidianPlugins.kanban;
settings = {
move-tags = true;
move-dates = true;
@@ -153,7 +151,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-languagetool;
pkg = obsidianPlugins.languagetool;
settings = {
shouldAutoCheck = true;
pickyMode = true;
@@ -162,7 +160,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-linter;
pkg = obsidianPlugins.linter;
settings = {
lintOnSave = true;
displayChanged = false;
@@ -302,7 +300,7 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-map-view;
pkg = obsidianPlugins.map-view;
settings = {
"markerIconRules" = [
{
@@ -388,21 +386,21 @@ in
};
}
{
pkg = selfPkgs.obsidian-plugin-minimal-settings;
pkg = obsidianPlugins.minimal-settings;
settings = {
editorFont = "var(--font-monospace)";
};
}
{
pkg = selfPkgs.obsidian-plugin-outliner;
pkg = obsidianPlugins.outliner;
settings = {
styleLists = false;
stickCursor = "never";
};
}
(selfPkgs.obsidian-plugin-style-settings)
(obsidianPlugins.style-settings)
{
pkg = selfPkgs.obsidian-plugin-tasks;
pkg = obsidianPlugins.tasks;
settings = {
globalQuery = "short mode";
globalFilter = "#todo";
@@ -548,10 +546,10 @@ in
};
};
}
(selfPkgs.obsidian-plugin-url-into-selection)
(obsidianPlugins.url-into-selection)
];
themes = [ selfPkgs.obsidian-theme-minimal ];
themes = with pkgs; [ obsidianThemes.minimal ];
hotkeys = {
"command-palette:open" = [ { key = "F1"; } ];

View File

@@ -10,14 +10,6 @@ let
hmConfig = config.home-manager.users.${user};
in
{
nixpkgs.overlays = [
(final: prev: {
spicetify-cli = prev.spicetify-cli.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./user-colors.patch ];
});
})
];
networking.firewall = {
allowedTCPPorts = [ 57621 ];
allowedUDPPorts = [ 5353 ];
@@ -69,9 +61,7 @@ in
"spotify/prefs.init" = {
source = ./config/prefs;
onChange = ''
${
inputs.lib.lib.${system}.runtime.merge.keyValue
} "${home}/.config/spotify/prefs.init" "${home}/.config/spotify/prefs"
${lib.runtime.merge.keyValue} "${home}/.config/spotify/prefs.init" "${home}/.config/spotify/prefs"
'';
};
@@ -79,9 +69,7 @@ in
source = ./config/prefs-user;
onChange = ''
user=$(cat "${hmConfig.sops.secrets."spotify/username".path}")
${
inputs.lib.lib.${system}.runtime.merge.keyValue
} "${home}/.config/spotify/prefs-user.init" "${home}/.config/spotify/Users/''${user}-user/prefs"
${lib.runtime.merge.keyValue} "${home}/.config/spotify/prefs-user.init" "${home}/.config/spotify/Users/''${user}-user/prefs"
'';
};
};

View File

@@ -1,31 +0,0 @@
diff --git a/src/apply/apply.go b/src/apply/apply.go
index 47f1346..47badab 100644
--- a/src/apply/apply.go
+++ b/src/apply/apply.go
@@ -2,6 +2,7 @@ package apply
import (
"fmt"
+ "errors"
"os"
"path/filepath"
"strings"
@@ -65,10 +66,17 @@ func AdditionalOptions(appsFolderPath string, flags Flag) {
// To not use custom css, set `themeFolder` to blank string
// To use default color scheme, set `scheme` to `nil`
func UserCSS(appsFolderPath, themeFolder string, scheme map[string]string) {
+ colorsSrc := os.Getenv("COLORS_CSS_PATH")
colorsDest := filepath.Join(appsFolderPath, "xpui", "colors.css")
- if err := os.WriteFile(colorsDest, []byte(getColorCSS(scheme)), 0700); err != nil {
+
+ if len(colorsSrc) == 0 {
+ utils.Fatal(errors.New("COLORS_CSS_PATH environment variable is not set"))
+ }
+
+ if err := os.Symlink(colorsSrc, colorsDest); err != nil {
utils.Fatal(err)
}
+
cssDest := filepath.Join(appsFolderPath, "xpui", "user.css")
if err := os.WriteFile(cssDest, []byte(getUserCSS(themeFolder)), 0700); err != nil {
utils.Fatal(err)