Compare commits
8 Commits
2391462500
...
09-20-d
Author | SHA1 | Date | |
---|---|---|---|
8034f79753 | |||
895dab9413 | |||
c4d42d79a0 | |||
ab90adee42 | |||
ac4e4c277d | |||
0e03b784a2 | |||
590b1b87ca | |||
c8325aafca |
@ -21,14 +21,14 @@ csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_catch = false
|
||||
csharp_new_line_before_else = false
|
||||
csharp_new_line_before_finally = false
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_open_brace = none
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
csharp_prefer_braces = false
|
||||
csharp_prefer_braces = true
|
||||
csharp_prefer_qualified_reference = true:error
|
||||
csharp_prefer_simple_default_expression = true:warning
|
||||
csharp_prefer_simple_using_statement = true:warning
|
||||
@ -106,101 +106,37 @@ dotnet_code_quality_unused_parameters = all
|
||||
dotnet_code_quality_unused_parameters = non_public
|
||||
dotnet_code_quality.CAXXXX.api_surface = private, internal
|
||||
dotnet_diagnostic.CA1001.severity = error # CA1001: Types that own disposable fields should be disposable
|
||||
dotnet_diagnostic.CA1001.severity = none # Question - CA1001: Types that own disposable fields should be disposable
|
||||
dotnet_diagnostic.CA1051.severity = error # CA1051: Do not declare visible instance fields
|
||||
dotnet_diagnostic.CA1051.severity = none # Question - CA1051: Do not declare visible instance fields
|
||||
dotnet_diagnostic.CA1416.severity = none # Question - CA1416: This call site is reachable on all platforms. 'EventLogEntryType.Error' is only supported on: 'windows'.
|
||||
dotnet_diagnostic.CA1510.severity = none # Question - CA1510: Use 'ArgumentNullException.ThrowIfNull' instead of explicitly throwing a new exception instance
|
||||
dotnet_diagnostic.CA1511.severity = warning # CA1511: Use 'ArgumentException.ThrowIfNullOrEmpty' instead of explicitly throwing a new exception instance
|
||||
dotnet_diagnostic.CA1513.severity = warning # Use 'ObjectDisposedException.ThrowIf' instead of explicitly throwing a new exception instance
|
||||
dotnet_diagnostic.CA1825.severity = warning # CA1825: Avoid zero-length array allocations
|
||||
dotnet_diagnostic.CA1829.severity = error # CA1829: Use Length/Count property instead of Count() when available
|
||||
dotnet_diagnostic.CA1829.severity = none # Question - CA1829: Use Length/Count property instead of Enumerable.Count method
|
||||
dotnet_diagnostic.CA1829.severity = warning # CA1829: Use Length/Count property instead of Count() when available
|
||||
dotnet_diagnostic.CA1834.severity = warning # CA1834: Consider using 'StringBuilder.Append(char)' when applicable
|
||||
dotnet_diagnostic.CA1860.severity = error # CA1860: Prefer comparing 'Count' to 0 rather than using 'Any()', both for clarity and for performance
|
||||
dotnet_diagnostic.CA1860.severity = none # Question - CA1860: Avoid using 'Enumerable.Any()' extension method
|
||||
dotnet_diagnostic.CA1862.severity = warning # CA1862: Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'
|
||||
dotnet_diagnostic.CA1862.severity = none # Question - CA1862: Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'
|
||||
dotnet_diagnostic.CA1869.severity = none # CA1869: Avoid creating a new 'JsonSerializerOptions' instance for every serialization operation. Cache and reuse instances instead.
|
||||
dotnet_diagnostic.CA2200.severity = none # Question - CA2200: Re-throwing caught exception changes stack information
|
||||
dotnet_diagnostic.CA2201.severity = none # CA2201: Exception type System.NullReferenceException is reserved by the runtime
|
||||
dotnet_diagnostic.CA2208.severity = none # Question - CA2208: Instantiate argument exceptions correctly
|
||||
dotnet_diagnostic.CA2211.severity = none # Question - CA2211: Non-constant fields should not be visible
|
||||
dotnet_diagnostic.CA2249.severity = none # Question - CA2249: Use 'string.Contains' instead of 'string.IndexOf' to improve readability
|
||||
dotnet_diagnostic.CA2253.severity = none # Question - CA2253: Named placeholders should not be numeric values
|
||||
dotnet_diagnostic.CA2254.severity = none # CA2254: The logging message template should not vary between calls to 'LoggerExtensions.LogInformation(ILogger, string?, params object?[])'
|
||||
dotnet_diagnostic.CS0103.severity = none # Question - CS0103: The name 'Functions' does not exist in the current context
|
||||
dotnet_diagnostic.CS0168.severity = none # Question - CS0168: The variable 'ex' is declared but never used
|
||||
dotnet_diagnostic.CS0219.severity = none # Question - CS0219: The variable 'result' is assigned but its value is never used
|
||||
dotnet_diagnostic.CS0618.severity = none # Question - CS0618: Compiler Warning (level 2)
|
||||
dotnet_diagnostic.CS0659.severity = none # Question - CS0659: Compiler Warning (level 3)
|
||||
dotnet_diagnostic.CS8600.severity = none # Question - CS8600: Converting null literal or possible null value to non-nullable type
|
||||
dotnet_diagnostic.CS8602.severity = none # Question - CS8602: Dereference of a possibly null reference.
|
||||
dotnet_diagnostic.CS8603.severity = none # Question - CS8603: Possible null reference return
|
||||
dotnet_diagnostic.CS8604.severity = none # Question - CS8604: Possible null reference argument for parameter.
|
||||
dotnet_diagnostic.CS0612.severity = none # Question - CS0612: is obsolete
|
||||
dotnet_diagnostic.CS8618.severity = none # Question - CS8618: Non-nullable variable must contain a non-null value when exiting constructor
|
||||
dotnet_diagnostic.CS8625.severity = none # Question - CS8625: Cannot convert null literal to non-nullable reference type.
|
||||
dotnet_diagnostic.CS8629.severity = none # Question - CS8629: Nullable value type may be null
|
||||
dotnet_diagnostic.CS8765.severity = none # Question - CS8765: Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)
|
||||
dotnet_diagnostic.IDE0001.severity = warning # IDE0001: Simplify name
|
||||
dotnet_diagnostic.IDE0002.severity = warning # Simplify (member access) - System.Version.Equals("1", "2"); Version.Equals("1", "2");
|
||||
dotnet_diagnostic.IDE0004.severity = warning # IDE0004: Cast is redundant.
|
||||
dotnet_diagnostic.IDE0004.severity = none # Question - IDE0004: Cast is redundant.
|
||||
dotnet_diagnostic.IDE0003.severity = none # Question - IDE0003: this and Me preferences
|
||||
dotnet_diagnostic.IDE0005.severity = error # Using directive is unnecessary
|
||||
dotnet_diagnostic.IDE0005.severity = none # Question - IDE0005: Remove unnecessary using directives
|
||||
dotnet_diagnostic.IDE0008.severity = none # Question - IDE0008: 'var' preferences
|
||||
dotnet_diagnostic.IDE0005.severity = warning # Using directive is unnecessary
|
||||
dotnet_diagnostic.IDE0010.severity = none # Add missing cases to switch statement (IDE0010)
|
||||
dotnet_diagnostic.IDE0017.severity = none # Question - IDE0017: Use object initializers
|
||||
dotnet_diagnostic.IDE0019.severity = none # Question - IDE0019: Use pattern matching to avoid 'as' followed by a 'null' check
|
||||
dotnet_diagnostic.IDE0021.severity = none # Question - IDE0021: Use expression body for constructors
|
||||
dotnet_diagnostic.IDE0022.severity = none # Question - IDE0022: Use expression body for methods
|
||||
dotnet_diagnostic.IDE0025.severity = none # Question - IDE0025: Use expression body for properties
|
||||
dotnet_diagnostic.IDE0027.severity = none # Question - IDE0027: Use expression body for accessor
|
||||
dotnet_diagnostic.IDE0028.severity = error # IDE0028: Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0028.severity = none # Question - IDE0028: Use collection initializers or expressions
|
||||
dotnet_diagnostic.IDE0031.severity = warning # Use null propagation (IDE0031)
|
||||
dotnet_diagnostic.IDE0031.severity = none # Question - IDE0031: Use null propagation (IDE0031)
|
||||
dotnet_diagnostic.IDE0032.severity = none # Question - IDE0032: Use auto-implemented property
|
||||
dotnet_diagnostic.IDE0037.severity = none # Question - IDE0037: Member name can be simplified
|
||||
dotnet_diagnostic.IDE0040.severity = none # Question - IDE0040: Add accessibility modifiers
|
||||
dotnet_diagnostic.IDE0041.severity = none # Question - IDE0041: Use 'is null' check
|
||||
dotnet_diagnostic.IDE0044.severity = none # Question - IDE0044: Add readonly modifier
|
||||
dotnet_diagnostic.IDE0047.severity = warning # IDE0047: Parentheses can be removed
|
||||
dotnet_diagnostic.IDE0047.severity = none # Question - IDE0047: Parentheses preferences
|
||||
dotnet_diagnostic.IDE0048.severity = none # Parentheses preferences (IDE0047 and IDE0048)
|
||||
dotnet_diagnostic.IDE0049.severity = warning # Use language keywords instead of framework type names for type references (IDE0049)
|
||||
dotnet_diagnostic.IDE0051.severity = error # Private member '' is unused [, ]
|
||||
dotnet_diagnostic.IDE0051.severity = none # Question - IDE0051: Remove unused private member
|
||||
dotnet_diagnostic.IDE0053.severity = none # Question - IDE0053: Use expression body for lambdas
|
||||
dotnet_diagnostic.IDE0054.severity = none # Question - IDE0054: Use compound assignment
|
||||
dotnet_diagnostic.IDE0055.severity = none # Question - IDE0055: Formatting rule
|
||||
dotnet_diagnostic.IDE0057.severity = none # Question - IDE0057: Substring can be simplified
|
||||
dotnet_diagnostic.IDE0058.severity = error # IDE0058: Expression value is never used
|
||||
dotnet_diagnostic.IDE0058.severity = none # Question - IDE0058: Remove unnecessary expression value
|
||||
dotnet_diagnostic.IDE0059.severity = none # Question - IDE0059: Remove unnecessary value assignment
|
||||
dotnet_diagnostic.IDE0058.severity = warning # IDE0058: Expression value is never used
|
||||
dotnet_diagnostic.IDE0060.severity = error # IDE0060: Remove unused parameter
|
||||
dotnet_diagnostic.IDE0060.severity = none # Question - IDE0060: Remove unused parameter
|
||||
dotnet_diagnostic.IDE0063.severity = none # Question - IDE0063: Use simple 'using' statement
|
||||
dotnet_diagnostic.IDE0066.severity = none # Question - IDE0066: Use switch expression
|
||||
dotnet_diagnostic.IDE0074.severity = warning # IDE0074: Use compound assignment
|
||||
dotnet_diagnostic.IDE0078.severity = none # Question - IDE0078: Use pattern matching
|
||||
dotnet_diagnostic.IDE0100.severity = none # Question - IDE0100: Remove redundant equality
|
||||
dotnet_diagnostic.IDE0090.severity = none # Question - IDE0090: Simplify new expression
|
||||
dotnet_diagnostic.IDE0130.severity = none # Namespace does not match folder structure (IDE0130)
|
||||
dotnet_diagnostic.IDE0161.severity = none # Question - IDE0161: Namespace declaration preferences
|
||||
dotnet_diagnostic.IDE0270.severity = none # Question - IDE0270: Null check can be simplified
|
||||
dotnet_diagnostic.IDE0270.severity = warning # IDE0270: Null check can be simplified
|
||||
dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]csharp(IDE0290)
|
||||
dotnet_diagnostic.IDE0300.severity = error # IDE0300: Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0065.severity = none # Question - IDE0065: 'using' directive placement
|
||||
dotnet_diagnostic.IDE0300.severity = none # Question - IDE0300: Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0301.severity = error #IDE0301: Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified
|
||||
dotnet_diagnostic.IDE1006.severity = none # Question - IDE1006: Use collection expression for builder dotnet_style_prefer_collection_expression
|
||||
dotnet_diagnostic.IDE2000.severity = error # IDE2000: Allow multiple blank lines
|
||||
dotnet_diagnostic.IDE2000.severity = none # Question - IDE2000: Allow multiple blank lines
|
||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning
|
||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case
|
||||
dotnet_naming_rule.abstract_method_should_be_pascal_case.symbols = abstract_method
|
||||
|
8
.vscode/bash.md
vendored
8
.vscode/bash.md
vendored
@ -15,3 +15,11 @@ dotnet run --project src/ImmichToSlideshow
|
||||
```bash 1731643960696 = 638672407606960000 = Thu Nov 14 2024 21:12:40 GMT-0700 (Mountain Standard Time)
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
```bash 1732418534573 = 638680153345730000 = Sat Nov 23 2024 20:22:14 GMT-0700 (Mountain Standard Time)
|
||||
# docker system prune
|
||||
docker build .
|
||||
docker login gitea.phares.duckdns.org:443
|
||||
docker tag fa136e5bb221 gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest
|
||||
docker push gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest
|
||||
```
|
||||
|
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@ -8,8 +8,8 @@
|
||||
"name": ".NET Core Launch (console)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/src/ImmichToSlideshow/bin/Debug/net8.0/ImmichToSlideshow.dll",
|
||||
"preLaunchTask": "Build",
|
||||
"program": "${workspaceFolder}/src/ImmichToSlideshow/bin/Debug/net9.0/ImmichToSlideshow.dll",
|
||||
"args": [
|
||||
"s",
|
||||
"test"
|
||||
@ -28,6 +28,24 @@
|
||||
"request": "launch",
|
||||
"name": "node Launch Current Opened File",
|
||||
"program": "${file}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Docker",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"sourceFileMap": {
|
||||
"/app": "${workspaceRoot}"
|
||||
},
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"pipeTransport": {
|
||||
"debuggerPath": "/root/vsdbg/vsdbg",
|
||||
"pipeProgram": "docker",
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"quoteArgs": false,
|
||||
"pipeArgs": [
|
||||
"exec -i immich-to-slideshow-server"
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
79
.vscode/settings.json
vendored
79
.vscode/settings.json
vendored
@ -1,4 +1,11 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.ffs_gui": "xml",
|
||||
"*.hurl": "http",
|
||||
"*.org": "ini",
|
||||
"*.net": "ini",
|
||||
"default": "ini"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.wordWrap": "off"
|
||||
},
|
||||
@ -11,15 +18,70 @@
|
||||
},
|
||||
"cSpell.words": [
|
||||
"accessibilities",
|
||||
"ackages",
|
||||
"Acks",
|
||||
"aspnet",
|
||||
"ASPNETCORE",
|
||||
"binlog",
|
||||
"buildhelp",
|
||||
"cachefile",
|
||||
"CAXXXX",
|
||||
"checkin",
|
||||
"codegen",
|
||||
"coveragexml",
|
||||
"csdef",
|
||||
"dbmdl",
|
||||
"dbproj",
|
||||
"DENITED",
|
||||
"Digi",
|
||||
"dlldata",
|
||||
"docstates",
|
||||
"ebug",
|
||||
"elease",
|
||||
"eleases",
|
||||
"esult",
|
||||
"Fractors",
|
||||
"gitea",
|
||||
"Immich",
|
||||
"Infineon",
|
||||
"Installshield",
|
||||
"iobj",
|
||||
"ipch",
|
||||
"ipdb",
|
||||
"jmconfig",
|
||||
"mfractor",
|
||||
"Npgsql",
|
||||
"Thumbhash"
|
||||
"Nsight",
|
||||
"ntvs",
|
||||
"NUNIT",
|
||||
"nupkg",
|
||||
"nvuser",
|
||||
"opendb",
|
||||
"opensdf",
|
||||
"paket",
|
||||
"Paket",
|
||||
"pidb",
|
||||
"psess",
|
||||
"PTVS",
|
||||
"publishproj",
|
||||
"publishsettings",
|
||||
"pycache",
|
||||
"rptproj",
|
||||
"rsuser",
|
||||
"schemaview",
|
||||
"Silverlight",
|
||||
"svclog",
|
||||
"Telerik's",
|
||||
"Thumbhash",
|
||||
"ublish",
|
||||
"uild",
|
||||
"userosscache",
|
||||
"userprefs",
|
||||
"vspscc",
|
||||
"vspx",
|
||||
"vssscc",
|
||||
"wwwroot",
|
||||
"xpress"
|
||||
],
|
||||
"rest-client.environmentVariables": {
|
||||
"$shared": {
|
||||
@ -27,8 +89,19 @@
|
||||
"reviewId": "asdfasdf"
|
||||
},
|
||||
"dev": {
|
||||
"host": "http://localhost:5003",
|
||||
"token": "ey..dev"
|
||||
"ownerId": "5f0b1052-466d-44de-a554-226d7256850d",
|
||||
"host": "https://localhost:5003",
|
||||
"token": "ey..dev",
|
||||
},
|
||||
"affirm": {
|
||||
"ownerId": "5f0b1052-466d-44de-a554-226d7256850d",
|
||||
"host": "https://immich-to-slideshow.affirm.duckdns.org/",
|
||||
"token": "ey..affirm"
|
||||
},
|
||||
"phares": {
|
||||
"ownerId": "5f0b1052-466d-44de-a554-226d7256850d",
|
||||
"host": "https://immich-to-slideshow.phares.duckdns.org/",
|
||||
"token": "ey..phares"
|
||||
}
|
||||
}
|
||||
}
|
86
.vscode/tasks.json
vendored
86
.vscode/tasks.json
vendored
@ -43,7 +43,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Format-Whitespaces",
|
||||
"label": "Format Whitespaces",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
@ -53,7 +53,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "build",
|
||||
"label": "Build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
@ -65,7 +65,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"label": "Publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
@ -77,7 +77,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"label": "Watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
@ -88,6 +88,84 @@
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Login",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"login",
|
||||
"gitea.phares.duckdns.org:443"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Compose Up Build",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"compose",
|
||||
"up",
|
||||
"--build"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Build",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"-t",
|
||||
"immich-to-slideshow",
|
||||
"."
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Image List",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"image",
|
||||
"ls"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Run",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"run",
|
||||
"-p",
|
||||
"5001:5001",
|
||||
"--name",
|
||||
"immich-to-slideshow_webapp",
|
||||
"a3de856b5731"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Tag",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"tag",
|
||||
"3f9eac99b7cf0710c5d762322ce4ded3f57fc008ee8310757760bb78ad8e029f",
|
||||
"gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Podman Push",
|
||||
"command": "podman",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"push",
|
||||
"gitea.phares.duckdns.org:443/phares3757/immich-to-slideshow:latest"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Publish AOT",
|
||||
"command": "dotnet",
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Stage 1: Build Stage
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
@ -17,14 +17,9 @@ FROM build AS publish
|
||||
RUN dotnet publish 'ImmichToSlideshow.csproj' -c Release -o /app/publish
|
||||
|
||||
# Stage 3: Run Stage
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0
|
||||
ENV ASPNETCORE_HTTP_PORTS=5001
|
||||
EXPOSE 5001
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT [ "dotnet", "ImmichToSlideshow.dll" ]
|
||||
|
||||
# docker build -t sprint-console-001 .
|
||||
# docker images ls | grep -i 001
|
||||
# docker run -p 5001:5001 --name sprint-console-api-001 sprint-console-001
|
||||
# docker run -p 5001:5001 --name sprint-console-api-001 sprint-console-001
|
@ -1,6 +1,6 @@
|
||||
services:
|
||||
webapp:
|
||||
container_name: immich-to-slideshow-api
|
||||
container_name: immich-to-slideshow
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"rollForward": "latestMinor",
|
||||
"version": "8.0.100"
|
||||
"version": "9.0.100"
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
@immich_to_slideshow_HostAddress = http://localhost:5243
|
||||
|
||||
GET {{immich_to_slideshow_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
80
requests/ImmichToSlideshow.hurl
Normal file
80
requests/ImmichToSlideshow.hurl
Normal file
@ -0,0 +1,80 @@
|
||||
GET http://127.0.0.1:5001/api/v1/assets/columns/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/owner-ids/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/random-paths/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/save-random-paths/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/sync-immich/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/set-archive-immich/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/set-digi-kam-4-archive-immich/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
||||
|
||||
GET http://127.0.0.1:5001/api/v1/assets/5f0b1052-466d-44de-a554-226d7256850d/archived-tag/
|
||||
Accept: application/json
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
header "Content-Type" == "application/json"
|
||||
|
||||
###
|
@ -1 +0,0 @@
|
||||
GET www.google.com
|
@ -1,93 +1,54 @@
|
||||
using ImmichToSlideshow.Models.Immich;
|
||||
using ImmichToSlideshow.Services;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace ImmichToSlideshow.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class AssetsController(AssetService assetService) : ControllerBase
|
||||
{
|
||||
[Route("api/v1/[controller]")]
|
||||
public class AssetsController(AssetService assetService) : ControllerBase {
|
||||
|
||||
private readonly string _ContentType = "application/json";
|
||||
private readonly AssetService _AssetService = assetService;
|
||||
|
||||
[HttpGet()]
|
||||
public IActionResult Get()
|
||||
{
|
||||
ReadOnlyCollection<Asset> assets = _AssetService.Get();
|
||||
AssetResponse?[] assetResponses = AssetResponse.FromDomain(assets);
|
||||
return Ok(assetResponses);
|
||||
}
|
||||
[HttpGet("columns")]
|
||||
public IActionResult GetColumns() =>
|
||||
Content(_AssetService.GetColumns() ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult Create(CreateAssetRequest request)
|
||||
{
|
||||
// mapping to internal representation
|
||||
Asset asset = request.ToDomain();
|
||||
[HttpGet("owner-ids")]
|
||||
public IActionResult GetOwnerIds() =>
|
||||
Content(_AssetService.GetOwnerIds() ?? string.Empty, _ContentType);
|
||||
|
||||
// invoke the use case
|
||||
_AssetService.Create(asset);
|
||||
[HttpGet("{ownerId:guid}")]
|
||||
public IActionResult Get(Guid ownerId) =>
|
||||
Content(_AssetService.GetAssets(ownerId) ?? string.Empty, _ContentType);
|
||||
|
||||
// mapping to external representation
|
||||
AssetResponse assetResponse = AssetResponse.FromDomain(asset);
|
||||
[HttpGet("{ownerId:guid}/random-paths")]
|
||||
public IActionResult GetRandomPaths(Guid ownerId) =>
|
||||
Ok(_AssetService.GetRandomPaths(ownerId, monthDay: null));
|
||||
|
||||
// return 201 created response
|
||||
return CreatedAtAction(
|
||||
actionName: nameof(Get),
|
||||
routeValues: new { AssetId = asset.Id },
|
||||
value: assetResponse);
|
||||
}
|
||||
[HttpGet("{ownerId:guid}/archived-tag")]
|
||||
public IActionResult GetArchivedTag(Guid ownerId) =>
|
||||
Content(_AssetService.GetArchivedTag(ownerId) ?? string.Empty, _ContentType);
|
||||
|
||||
[HttpGet("{assetId:guid}")]
|
||||
public IActionResult Get(Guid assetId)
|
||||
{
|
||||
//get the asset
|
||||
Asset? asset = _AssetService.Get(assetId);
|
||||
[HttpGet("{ownerId:guid}/save-random-paths")]
|
||||
public IActionResult SaveRandomPaths(Guid ownerId, string? month_day) =>
|
||||
Content(_AssetService.SaveRandomPaths(ownerId, monthDay: month_day) ?? string.Empty, _ContentType);
|
||||
|
||||
// mapping to external representation
|
||||
AssetResponse? assetResponse = AssetResponse.FromDomain(asset);
|
||||
[HttpGet("{ownerId:guid}/sync-immich")]
|
||||
public IActionResult SyncImmich(Guid ownerId) =>
|
||||
Ok(_AssetService.SyncImmich(ownerId));
|
||||
|
||||
// return 200 ok response
|
||||
return assetResponse is null
|
||||
? Problem(statusCode: StatusCodes.Status404NotFound, detail: $"Asset not found {assetId}")
|
||||
: Ok(assetResponse);
|
||||
}
|
||||
[HttpGet("{ownerId:guid}/set-archive-immich")]
|
||||
public IActionResult SetArchiveImmich(Guid ownerId) =>
|
||||
Ok(_AssetService.SetArchiveImmich(ownerId));
|
||||
|
||||
public record CreateAssetRequest(string Id,
|
||||
string DeviceAssetId,
|
||||
string OwnerId,
|
||||
string OriginalFileName,
|
||||
string Path)
|
||||
{
|
||||
[HttpGet("{ownerId:guid}/set-digi-kam-4-archive-immich")]
|
||||
public IActionResult SetDigiKam4ArchiveImmich(Guid ownerId) =>
|
||||
Ok(_AssetService.SetDigiKam4ArchiveImmich(ownerId));
|
||||
|
||||
public Asset ToDomain() =>
|
||||
Asset.Get(id: Id,
|
||||
deviceAssetId: DeviceAssetId,
|
||||
ownerId: OwnerId,
|
||||
originalFileName: OriginalFileName,
|
||||
path: Path);
|
||||
|
||||
}
|
||||
|
||||
public record AssetResponse(string Id,
|
||||
string DeviceAssetId,
|
||||
string OwnerId,
|
||||
string OriginalFileName,
|
||||
string Path)
|
||||
{
|
||||
|
||||
public static AssetResponse? FromDomain(Asset? asset) =>
|
||||
asset is null ? null : new AssetResponse(
|
||||
Id: asset.Id,
|
||||
DeviceAssetId: asset.DeviceAssetId,
|
||||
OwnerId: asset.OwnerId,
|
||||
OriginalFileName: asset.OriginalFileName,
|
||||
Path: asset.Path);
|
||||
|
||||
public static AssetResponse?[] FromDomain(IEnumerable<Asset> assets) =>
|
||||
assets.Select(FromDomain).ToArray();
|
||||
|
||||
}
|
||||
[HttpGet("update-assets-set-local-date-time-for-three-and-seven")]
|
||||
public IActionResult UpdateAssetsSetLocalDateTimeForThreeAndSeven() =>
|
||||
Ok(_AssetService.UpdateAssetsSetLocalDateTimeForThreeAndSeven());
|
||||
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
using ImmichToSlideshow.Models;
|
||||
using ImmichToSlideshow.Services;
|
||||
|
||||
namespace ImmichToSlideshow.DependencyInjection;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
public static IServiceCollection AddServices(this IServiceCollection services)
|
||||
{
|
||||
public static IServiceCollection AddServices(this IServiceCollection services, AppSettings appSettings) {
|
||||
_ = services.AddControllers();
|
||||
_ = services.AddScoped<AssetService>();
|
||||
_ = services.AddSingleton(_ => appSettings);
|
||||
return services;
|
||||
}
|
||||
|
||||
|
74
src/ImmichToSlideshow/Domain/ImageTag.cs
Normal file
74
src/ImmichToSlideshow/Domain/ImageTag.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using ImmichToSlideshow.Models.DigiKam;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
// Business concerns
|
||||
|
||||
public record ImageTag(long Id,
|
||||
string Name,
|
||||
string Tag) {
|
||||
|
||||
internal static ReadOnlyCollection<ImageTag>? Get(string tag, string? tagsPath, string? imageTagsPath, string? imagesPath) {
|
||||
List<ImageTag>? results;
|
||||
ReadOnlyCollection<Tags>? tags = Tags.GetTags(tagsPath);
|
||||
if (tags is null || tags.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<int> tagIds = GetTagIds(tag, tags);
|
||||
if (tagIds.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<ImageTags>? imageTags = ImageTags.GetImageTags(imageTagsPath);
|
||||
if (imageTags is null || imageTags.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
ReadOnlyCollection<int> imageIds = GetImageIds(imageTags, tagIds);
|
||||
if (imageIds.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
results = [];
|
||||
long id;
|
||||
ImageTag imageTag;
|
||||
ReadOnlyCollection<Images>? images = Images.GetImages(imagesPath);
|
||||
if (images is null || images.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
foreach (Images i in images) {
|
||||
if (!imageIds.Contains(i.Id) || !long.TryParse(i.Name.Split('.')[0], out id)) {
|
||||
continue;
|
||||
}
|
||||
imageTag = new(Id: id, Name: i.Name, Tag: tag);
|
||||
results.Add(imageTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetTagIds(string tag, ReadOnlyCollection<Tags> tags) {
|
||||
List<int> results = [];
|
||||
foreach (Tags t in tags) {
|
||||
if (t.Name != tag) {
|
||||
continue;
|
||||
}
|
||||
results.Add(t.Id);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int> GetImageIds(ReadOnlyCollection<ImageTags> imageTags, ReadOnlyCollection<int> tagIds) {
|
||||
List<int> results = [];
|
||||
foreach (ImageTags i in imageTags) {
|
||||
if (!tagIds.Contains(i.TagId)) {
|
||||
continue;
|
||||
}
|
||||
results.Add(i.ImageId);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +1,8 @@
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
public class Product
|
||||
{
|
||||
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
public required string Name { get; init; }
|
||||
public required string Category { get; init; }
|
||||
public required string SubCategory { get; init; }
|
||||
|
||||
// Business concerns
|
||||
|
||||
}
|
||||
public record Product(Guid Id,
|
||||
string Name,
|
||||
string Category,
|
||||
string SubCategory);
|
@ -1,14 +1,11 @@
|
||||
namespace ImmichToSlideshow.Domain;
|
||||
|
||||
public class User
|
||||
{
|
||||
// Business concerns
|
||||
|
||||
public Guid Id { get; init; } = Guid.NewGuid();
|
||||
public List<Product> Products { get; init; } = [];
|
||||
public record User(Guid Id,
|
||||
List<Product> Products) {
|
||||
|
||||
internal void AddProduct(Product product) =>
|
||||
Products.Add(product);
|
||||
|
||||
// Business concerns
|
||||
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<UserSecretsId>cc24ad7a-1d95-4c47-a3ea-0d8475ab06da</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql" Version="9.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -3,21 +3,87 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public record AppSettings(string Company,
|
||||
string ConnectionString,
|
||||
string WorkingDirectoryName)
|
||||
{
|
||||
public record AppSettings(string Company, Settings Settings, string URLs, string[] WithOrigins) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void Verify(AppSettings appSettings) {
|
||||
if (appSettings?.Company is null) {
|
||||
throw new NullReferenceException(nameof(Company));
|
||||
}
|
||||
if (appSettings?.URLs is null) {
|
||||
throw new NullReferenceException(nameof(URLs));
|
||||
}
|
||||
if (appSettings?.WithOrigins is null) {
|
||||
throw new NullReferenceException(nameof(WithOrigins));
|
||||
}
|
||||
if (appSettings?.Settings?.AddDays is null) {
|
||||
throw new NullReferenceException(nameof(Settings.AddDays));
|
||||
}
|
||||
if (appSettings?.Settings?.BirthdayFormat is null) {
|
||||
throw new NullReferenceException(nameof(Settings.BirthdayFormat));
|
||||
}
|
||||
if (appSettings?.Settings?.ArchivedTag is null) {
|
||||
throw new NullReferenceException(nameof(Settings.ArchivedTag));
|
||||
}
|
||||
if (appSettings?.Settings?.ConnectionString is null) {
|
||||
throw new NullReferenceException(nameof(Settings.ConnectionString));
|
||||
}
|
||||
if (appSettings?.Settings?.DigiKam4 is null) {
|
||||
throw new NullReferenceException(nameof(Settings.DigiKam4));
|
||||
}
|
||||
if (appSettings?.Settings?.FilterTags is null) {
|
||||
throw new NullReferenceException(nameof(Settings.FilterTags));
|
||||
}
|
||||
if (appSettings?.Settings?.ImmichUploadDirectory is null) {
|
||||
throw new NullReferenceException(nameof(Settings.ImmichUploadDirectory));
|
||||
}
|
||||
if (appSettings?.Settings?.People is null) {
|
||||
throw new NullReferenceException(nameof(Settings.People));
|
||||
}
|
||||
if (appSettings?.Settings?.RandomResultsDirectory is null) {
|
||||
throw new NullReferenceException(nameof(Settings.RandomResultsDirectory));
|
||||
}
|
||||
if (appSettings?.Settings?.SyncDirectory is null) {
|
||||
throw new NullReferenceException(nameof(Settings.SyncDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
public static AppSettings Get(IConfigurationRoot configurationRoot) {
|
||||
AppSettings result;
|
||||
#pragma warning disable IL3050, IL2026
|
||||
string? urls = configurationRoot.GetSection(nameof(URLs)).Get<string>();
|
||||
string? company = configurationRoot.GetSection(nameof(Company)).Get<string>();
|
||||
Settings? settings = configurationRoot.GetSection(nameof(Settings)).Get<Settings>();
|
||||
string[]? withOrigins = configurationRoot.GetSection(nameof(WithOrigins)).Get<string[]>();
|
||||
#pragma warning restore IL3050, IL2026
|
||||
if (company is null || settings is null || urls is null || withOrigins is null) {
|
||||
List<string> paths = [];
|
||||
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers) {
|
||||
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider) {
|
||||
continue;
|
||||
}
|
||||
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider) {
|
||||
continue;
|
||||
}
|
||||
paths.Add(physicalFileProvider.Root);
|
||||
}
|
||||
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
|
||||
}
|
||||
result = new(Company: company,
|
||||
Settings: settings,
|
||||
URLs: urls,
|
||||
WithOrigins: withOrigins);
|
||||
Verify(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(AppSettings))]
|
||||
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
[*.cs]
|
||||
csharp_preserve_single_line_statements = true
|
@ -1,65 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.Binder;
|
||||
|
||||
public class AppSettings
|
||||
{
|
||||
|
||||
public string? Company { get; set; }
|
||||
public string? ConnectionString { get; set; }
|
||||
public string? WorkingDirectoryName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, BinderAppSettingsSourceGenerationContext.Default.AppSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void PreVerify(IConfigurationRoot configurationRoot, AppSettings? appSettings)
|
||||
{
|
||||
if (appSettings?.Company is null)
|
||||
{
|
||||
List<string> paths = [];
|
||||
foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers)
|
||||
{
|
||||
if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider)
|
||||
continue;
|
||||
if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider)
|
||||
continue;
|
||||
paths.Add(physicalFileProvider.Root);
|
||||
}
|
||||
throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}");
|
||||
}
|
||||
}
|
||||
|
||||
private static Models.AppSettings Get(AppSettings? appSettings)
|
||||
{
|
||||
Models.AppSettings result;
|
||||
if (appSettings?.Company is null) throw new NullReferenceException(nameof(appSettings.Company));
|
||||
if (appSettings?.ConnectionString is null) throw new NullReferenceException(nameof(appSettings.ConnectionString));
|
||||
if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName));
|
||||
result = new(appSettings.Company,
|
||||
appSettings.ConnectionString,
|
||||
appSettings.WorkingDirectoryName);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
|
||||
{
|
||||
Models.AppSettings result;
|
||||
#pragma warning disable IL3050, IL2026
|
||||
AppSettings? appSettings = configurationRoot.Get<AppSettings>();
|
||||
#pragma warning restore IL3050, IL2026
|
||||
PreVerify(configurationRoot, appSettings);
|
||||
result = Get(appSettings);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(AppSettings))]
|
||||
internal partial class BinderAppSettingsSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
11
src/ImmichToSlideshow/Models/DigiKam/AlbumRoots.cs
Normal file
11
src/ImmichToSlideshow/Models/DigiKam/AlbumRoots.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record AlbumRoots([property: JsonPropertyName("caseSensitivity")] int CaseSensitivity,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("identifier")] string Identifier,
|
||||
[property: JsonPropertyName("label")] string Label,
|
||||
[property: JsonPropertyName("specificPath")] string SpecificPath,
|
||||
[property: JsonPropertyName("status")] int Status,
|
||||
[property: JsonPropertyName("type")] int Type);
|
12
src/ImmichToSlideshow/Models/DigiKam/Albums.cs
Normal file
12
src/ImmichToSlideshow/Models/DigiKam/Albums.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Albums([property: JsonPropertyName("albumRoot")] int AlbumRoot,
|
||||
[property: JsonPropertyName("caption")] object Caption,
|
||||
[property: JsonPropertyName("collection")] object Collection,
|
||||
[property: JsonPropertyName("date")] string Date,
|
||||
[property: JsonPropertyName("icon")] object Icon,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("modificationDate")] DateTime ModificationDate,
|
||||
[property: JsonPropertyName("relativePath")] string RelativePath);
|
11
src/ImmichToSlideshow/Models/DigiKam/ImageComments.cs
Normal file
11
src/ImmichToSlideshow/Models/DigiKam/ImageComments.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageComments([property: JsonPropertyName("author")] object Author,
|
||||
[property: JsonPropertyName("comment")] string Comment,
|
||||
[property: JsonPropertyName("date")] object Date,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("language")] string Language,
|
||||
[property: JsonPropertyName("type")] int Type);
|
15
src/ImmichToSlideshow/Models/DigiKam/ImagePositions.cs
Normal file
15
src/ImmichToSlideshow/Models/DigiKam/ImagePositions.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImagePositions([property: JsonPropertyName("accuracy")] object Accuracy,
|
||||
[property: JsonPropertyName("altitude")] double? Altitude,
|
||||
[property: JsonPropertyName("description")] object Description,
|
||||
[property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("latitude")] string Latitude,
|
||||
[property: JsonPropertyName("latitudeNumber")] double? LatitudeNumber,
|
||||
[property: JsonPropertyName("longitude")] string Longitude,
|
||||
[property: JsonPropertyName("longitudeNumber")] double? LongitudeNumber,
|
||||
[property: JsonPropertyName("orientation")] object Orientation,
|
||||
[property: JsonPropertyName("roll")] object Roll,
|
||||
[property: JsonPropertyName("tilt")] object Tilt);
|
@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageTagProperties([property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("property")] string Property,
|
||||
[property: JsonPropertyName("tagid")] int TagId,
|
||||
[property: JsonPropertyName("value")] string Value);
|
21
src/ImmichToSlideshow/Models/DigiKam/ImageTags.cs
Normal file
21
src/ImmichToSlideshow/Models/DigiKam/ImageTags.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record ImageTags([property: JsonPropertyName("imageid")] int ImageId,
|
||||
[property: JsonPropertyName("tagid")] int TagId) {
|
||||
|
||||
internal static ReadOnlyCollection<ImageTags>? GetImageTags(string? path) {
|
||||
ImageTags[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<ImageTags[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
28
src/ImmichToSlideshow/Models/DigiKam/Images.cs
Normal file
28
src/ImmichToSlideshow/Models/DigiKam/Images.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Images([property: JsonPropertyName("album")] int? Album,
|
||||
[property: JsonPropertyName("category")] int Category,
|
||||
[property: JsonPropertyName("fileSize")] object FileSize,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("manualOrder")] object ManualOrder,
|
||||
[property: JsonPropertyName("modificationDate")] DateTime ModificationDate,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("status")] int Status,
|
||||
[property: JsonPropertyName("uniqueHash")] string UniqueHash) {
|
||||
|
||||
internal static ReadOnlyCollection<Images>? GetImages(string? path) {
|
||||
Images[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<Images[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
7
src/ImmichToSlideshow/Models/DigiKam/TagProperties.cs
Normal file
7
src/ImmichToSlideshow/Models/DigiKam/TagProperties.cs
Normal file
@ -0,0 +1,7 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record TagProperties([property: JsonPropertyName("property")] string Property,
|
||||
[property: JsonPropertyName("tagid")] int TagId,
|
||||
[property: JsonPropertyName("value")] object Value);
|
24
src/ImmichToSlideshow/Models/DigiKam/Tags.cs
Normal file
24
src/ImmichToSlideshow/Models/DigiKam/Tags.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.DigiKam;
|
||||
|
||||
public record Tags([property: JsonPropertyName("icon")] object Icon,
|
||||
[property: JsonPropertyName("iconkde")] object IconKDE,
|
||||
[property: JsonPropertyName("id")] int Id,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("pid")] int PId) {
|
||||
|
||||
internal static ReadOnlyCollection<Tags>? GetTags(string? path) {
|
||||
Tags[]? results;
|
||||
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(path);
|
||||
results = JsonSerializer.Deserialize<Tags[]>(json);
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
22
src/ImmichToSlideshow/Models/DigiKam4.cs
Normal file
22
src/ImmichToSlideshow/Models/DigiKam4.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public record DigiKam4(string Images,
|
||||
string ImageTagProperties,
|
||||
string ImageTags,
|
||||
string TagProperties,
|
||||
string Tags) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, DigiKam4SourceGenerationContext.Default.DigiKam4);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(DigiKam4))]
|
||||
public partial class DigiKam4SourceGenerationContext : JsonSerializerContext {
|
||||
}
|
40
src/ImmichToSlideshow/Models/Identifier.cs
Normal file
40
src/ImmichToSlideshow/Models/Identifier.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using ImmichToSlideshow.Domain;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public sealed record Identifier(string[] DirectoryNames,
|
||||
string Extension,
|
||||
bool? HasDateTimeOriginal,
|
||||
int Id,
|
||||
long Length,
|
||||
string PaddedId,
|
||||
long Ticks) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, IdentifierSourceGenerationContext.Default.Identifier);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string GetDeviceAssetIds(ReadOnlyCollection<Identifier> identifiers) =>
|
||||
$"'{string.Join($"',{Environment.NewLine}'", (from l in identifiers select GetDeviceAssetId(l)).ToArray())}'";
|
||||
|
||||
internal static string GetDeviceAssetIds(ReadOnlyCollection<ImageTag> imageTags) =>
|
||||
$"'{string.Join($"',{Environment.NewLine}'", (from l in imageTags select l.Name).ToArray())}'";
|
||||
|
||||
internal static string GetDeviceAssetId(Identifier identifier) =>
|
||||
$"{identifier.PaddedId}{identifier.Extension}";
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier))]
|
||||
public partial class IdentifierSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier[]))]
|
||||
public partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -5,58 +5,47 @@ namespace ImmichToSlideshow.Models.Immich;
|
||||
|
||||
public record Asset([property: JsonPropertyName("id")] string Id,
|
||||
[property: JsonPropertyName("deviceAssetId")] string DeviceAssetId,
|
||||
[property: JsonPropertyName("ownerId")] string OwnerId,
|
||||
[property: JsonPropertyName("deviceId")] string DeviceId,
|
||||
[property: JsonPropertyName("type")] string Type,
|
||||
// [property: JsonPropertyName("ownerId")] string OwnerId,
|
||||
// [property: JsonPropertyName("deviceId")] string DeviceId,
|
||||
// [property: JsonPropertyName("type")] string Type,
|
||||
[property: JsonPropertyName("originalPath")] string OriginalPath,
|
||||
[property: JsonPropertyName("fileCreatedAt")] DateTime FileCreatedAt,
|
||||
[property: JsonPropertyName("fileModifiedAt")] DateTime FileModifiedAt,
|
||||
[property: JsonPropertyName("isFavorite")] bool IsFavorite,
|
||||
[property: JsonPropertyName("duration")] string Duration,
|
||||
[property: JsonPropertyName("encodedVideoPath")] string EncodedVideoPath,
|
||||
[property: JsonPropertyName("checksum")] string Checksum,
|
||||
[property: JsonPropertyName("isVisible")] bool IsVisible,
|
||||
[property: JsonPropertyName("livePhotoVideoId")] object LivePhotoVideoId,
|
||||
[property: JsonPropertyName("updatedAt")] DateTime UpdatedAt,
|
||||
[property: JsonPropertyName("createdAt")] DateTime CreatedAt,
|
||||
[property: JsonPropertyName("isArchived")] bool IsArchived,
|
||||
// [property: JsonPropertyName("fileCreatedAt")] DateTime FileCreatedAt,
|
||||
// [property: JsonPropertyName("fileModifiedAt")] DateTime FileModifiedAt,
|
||||
// [property: JsonPropertyName("isFavorite")] bool IsFavorite,
|
||||
// [property: JsonPropertyName("duration")] string? Duration,
|
||||
// [property: JsonPropertyName("encodedVideoPath")] string EncodedVideoPath,
|
||||
// [property: JsonPropertyName("checksum")] string Checksum,
|
||||
// [property: JsonPropertyName("isVisible")] bool IsVisible,
|
||||
// [property: JsonPropertyName("livePhotoVideoId")] object? LivePhotoVideoId,
|
||||
// [property: JsonPropertyName("updatedAt")] DateTime UpdatedAt,
|
||||
// [property: JsonPropertyName("createdAt")] DateTime CreatedAt,
|
||||
// [property: JsonPropertyName("isArchived")] bool IsArchived,
|
||||
[property: JsonPropertyName("originalFileName")] string OriginalFileName,
|
||||
[property: JsonPropertyName("sidecarPath")] object SidecarPath,
|
||||
[property: JsonPropertyName("thumbhash")] string Thumbhash,
|
||||
[property: JsonPropertyName("isOffline")] bool IsOffline,
|
||||
[property: JsonPropertyName("libraryId")] string LibraryId,
|
||||
[property: JsonPropertyName("isExternal")] bool IsExternal,
|
||||
[property: JsonPropertyName("deletedAt")] object DeletedAt,
|
||||
[property: JsonPropertyName("localDateTime")] DateTime LocalDateTime,
|
||||
[property: JsonPropertyName("stackId")] object StackId,
|
||||
[property: JsonPropertyName("duplicateId")] string DuplicateId,
|
||||
[property: JsonPropertyName("status")] string Status,
|
||||
[property: JsonPropertyName("path")] string Path)
|
||||
{
|
||||
// [property: JsonPropertyName("sidecarPath")] object? SidecarPath,
|
||||
// [property: JsonPropertyName("thumbhash")] string Thumbhash,
|
||||
// [property: JsonPropertyName("isOffline")] bool IsOffline,
|
||||
// [property: JsonPropertyName("libraryId")] string LibraryId,
|
||||
// [property: JsonPropertyName("isExternal")] bool IsExternal,
|
||||
// [property: JsonPropertyName("deletedAt")] object? DeletedAt,
|
||||
// [property: JsonPropertyName("localDateTime")] DateTime LocalDateTime,
|
||||
// [property: JsonPropertyName("stackId")]? object? StackId,
|
||||
[property: JsonPropertyName("duplicateId")] string? DuplicateId,
|
||||
// [property: JsonPropertyName("status")] string Status,
|
||||
[property: JsonPropertyName("path")] string Path) {
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, AssetSourceGenerationContext.Default.Asset);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Asset Get(string id,
|
||||
string deviceAssetId,
|
||||
string ownerId,
|
||||
string originalFileName,
|
||||
string path) =>
|
||||
throw new Exception();
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Asset))]
|
||||
internal partial class AssetSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AssetSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Asset[]))]
|
||||
internal partial class AssetCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
internal partial class AssetCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
30
src/ImmichToSlideshow/Models/Immich/Tag.cs
Normal file
30
src/ImmichToSlideshow/Models/Immich/Tag.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models.Immich;
|
||||
|
||||
public record Tag([property: JsonPropertyName("id")] string Id,
|
||||
[property: JsonPropertyName("userId")] string UserId,
|
||||
[property: JsonPropertyName("value")] string OwnerId,
|
||||
// [property: JsonPropertyName("createdAt")] DateTime CreatedAt,
|
||||
// [property: JsonPropertyName("updatedAt")] DateTime UpdatedAt,
|
||||
// [property: JsonPropertyName("color")] char Color,
|
||||
// [property: JsonPropertyName("parentId")] string ParentId,
|
||||
[property: JsonPropertyName("updateId")] string UpdateId) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, TagSourceGenerationContext.Default.Tag);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Tag))]
|
||||
internal partial class TagSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Tag[]))]
|
||||
internal partial class TagCollectionSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
29
src/ImmichToSlideshow/Models/Settings.cs
Normal file
29
src/ImmichToSlideshow/Models/Settings.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ImmichToSlideshow.Models;
|
||||
|
||||
public record Settings(int AddDays,
|
||||
string ArchivedTag,
|
||||
string BirthdayFormat,
|
||||
string ConnectionString,
|
||||
DigiKam4? DigiKam4,
|
||||
string[] FilterTags,
|
||||
string ImmichUploadDirectory,
|
||||
float LowestVersionHistory,
|
||||
string NotNinePath,
|
||||
Dictionary<string, string> People,
|
||||
string RandomResultsDirectory,
|
||||
string SyncDirectory) {
|
||||
|
||||
public override string ToString() {
|
||||
string result = JsonSerializer.Serialize(this, SettingsSourceGenerationContext.Default.Settings);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Settings))]
|
||||
public partial class SettingsSourceGenerationContext : JsonSerializerContext {
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
namespace ImmichToSlideshow.Persistence.Database;
|
||||
|
||||
public static class DbConstants
|
||||
{
|
||||
public static class DbConstants {
|
||||
|
||||
public const string DefaultConnectionStringPath = "Database:ConnectionStrings:DefaultConnection";
|
||||
|
||||
|
@ -2,21 +2,22 @@ using ImmichToSlideshow.DependencyInjection;
|
||||
using ImmichToSlideshow.Models;
|
||||
using ImmichToSlideshow.RequestPipeline;
|
||||
|
||||
namespace ImmichToSlideshow;
|
||||
|
||||
public class Program {
|
||||
|
||||
public static void Main(string[] args) {
|
||||
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(args);
|
||||
{
|
||||
// configure services (DI)
|
||||
_ = webApplicationBuilder.Services.AddServices();
|
||||
_ = webApplicationBuilder.Services.AddControllers();
|
||||
_ = webApplicationBuilder.Configuration.AddUserSecrets<Program>();
|
||||
AppSettings appSettings = ImmichToSlideshow.Models.Binder.AppSettings.Get(webApplicationBuilder.Configuration);
|
||||
_ = webApplicationBuilder.Services.AddSingleton(_ => appSettings);
|
||||
}
|
||||
AppSettings appSettings = AppSettings.Get(webApplicationBuilder.Configuration);
|
||||
_ = webApplicationBuilder.Services.AddServices(appSettings);
|
||||
WebApplication webApplication = webApplicationBuilder.Build();
|
||||
{
|
||||
// configure request pipeline
|
||||
_ = webApplication.MapControllers();
|
||||
_ = webApplication.InitializeDatabase();
|
||||
}
|
||||
ILogger<Program>? logger = webApplication.Services.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogInformation("Starting Web Application");
|
||||
_ = webApplication.InitializeCorsAndHttps(appSettings);
|
||||
_ = webApplication.MapControllers();
|
||||
_ = webApplication.InitializeDatabase();
|
||||
webApplication.Run();
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +1,21 @@
|
||||
using ImmichToSlideshow.Models;
|
||||
|
||||
namespace ImmichToSlideshow.RequestPipeline;
|
||||
|
||||
public static class WebApplicationExtensions
|
||||
{
|
||||
public static class WebApplicationExtensions {
|
||||
|
||||
public static WebApplication InitializeDatabase(this WebApplication application)
|
||||
{
|
||||
public static WebApplication InitializeDatabase(this WebApplication webApplication) =>
|
||||
// DBInitializer.Initialize(application.Configuration[DbConstants.DefaultConnectionStringPath]!);
|
||||
return application;
|
||||
webApplication;
|
||||
|
||||
public static WebApplication InitializeCorsAndHttps(this WebApplication webApplication, AppSettings appSettings) {
|
||||
_ = webApplication.UseCors(corsPolicyBuilder =>
|
||||
corsPolicyBuilder.WithOrigins(appSettings.WithOrigins).AllowAnyHeader().AllowAnyMethod());
|
||||
if (appSettings.URLs.Contains("https", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
_ = webApplication.UseHttpsRedirection();
|
||||
_ = webApplication.UseHsts();
|
||||
}
|
||||
return webApplication;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using ImmichToSlideshow.Models.Immich;
|
||||
using ImmichToSlideshow.Domain;
|
||||
using ImmichToSlideshow.Models;
|
||||
using ImmichToSlideshow.Models.Immich;
|
||||
using Npgsql;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
@ -8,116 +9,275 @@ using System.Text.Json;
|
||||
|
||||
namespace ImmichToSlideshow.Services;
|
||||
|
||||
public class AssetService
|
||||
{
|
||||
public class AssetService(ILogger<Program> logger, AppSettings appSettings) {
|
||||
|
||||
private readonly AppSettings _AppSettings;
|
||||
#pragma warning disable CS9124
|
||||
private readonly ILogger<Program> _Logger = logger;
|
||||
private readonly Settings _Settings = appSettings.Settings;
|
||||
#pragma warning restore CS9124
|
||||
|
||||
public AssetService(AppSettings appSettings) =>
|
||||
_AppSettings = appSettings;
|
||||
|
||||
private static readonly List<Asset> _AssetsRepository = [];
|
||||
|
||||
private static string GetCommandText()
|
||||
{ // cSpell:disable
|
||||
List<string> results = new();
|
||||
// results.Add(" SELECT COALESCE(SUM(checksum_failures), 0) ");
|
||||
// results.Add(" FROM pg_stat_database ");
|
||||
// results.Add(" SELECT json_agg(t) ");
|
||||
// results.Add(" FROM information_schema.tables t ");
|
||||
// results.Add(" WHERE table_schema='public' ");
|
||||
// results.Add(" AND table_type='BASE TABLE' ");
|
||||
// results.Add(" SELECT json_agg(c) ");
|
||||
// results.Add(" FROM information_schema.columns c ");
|
||||
// results.Add(" WHERE table_name ='assets' ");
|
||||
// results.Add(" WHERE table_name ='libraries' ");
|
||||
// results.Add(" WHERE table_name ='asset_files' ");
|
||||
results.Add(" SELECT json_agg(j) ");
|
||||
results.Add(" FROM ( ");
|
||||
results.Add(" SELECT a.* ");
|
||||
results.Add(" , f.\"path\" ");
|
||||
results.Add(" FROM assets a ");
|
||||
// results.Add(" FROM asset_files f ");
|
||||
results.Add(" INNER ");
|
||||
results.Add(" JOIN asset_files f ");
|
||||
results.Add(" ON a.\"id\" = f.\"assetId\" ");
|
||||
results.Add(" AND f.\"type\" = 'preview' ");
|
||||
results.Add(" WHERE a.\"status\" = 'active' ");
|
||||
// results.Add(" WHERE f.\"assetId\" = '4c1933ce-f5b3-4348-bcc3-978f99823d70' ");
|
||||
results.Add(" AND a.\"isExternal\" = true ");
|
||||
results.Add(" AND a.\"isOffline\" = false ");
|
||||
results.Add(" AND a.\"isVisible\" = true ");
|
||||
// results.Add(" AND a.\"id\" = '4c1933ce-f5b3-4348-bcc3-978f99823d70' ");
|
||||
// results.Add(" AND a.\"originalFileName\"");
|
||||
// results.Add(" LIKE '%still%' ");
|
||||
// results.Add(" AND a.\"originalFileName\" = '979270910999.jpg' ");
|
||||
results.Add(" ) j ");
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
private static int? ExecuteNonQuery(string connectionString, string commandText)
|
||||
{
|
||||
private static int? ExecuteNonQuery(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters) {
|
||||
int? result;
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
if (string.IsNullOrEmpty(connectionString)) {
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
using NpgsqlConnection npgsqlConnection = new(connectionString);
|
||||
npgsqlConnection.Open();
|
||||
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
|
||||
npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray());
|
||||
result = npgsqlCommand.ExecuteNonQuery();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static StringBuilder GetForJsonPath(string connectionString, string commandText)
|
||||
{
|
||||
StringBuilder stringBuilder = new();
|
||||
private static StringBuilder GetForJsonPath(string connectionString, string commandText, ReadOnlyCollection<NpgsqlParameter> npgsqlParameters) {
|
||||
StringBuilder result = new();
|
||||
using NpgsqlConnection npgsqlConnection = new(connectionString);
|
||||
npgsqlConnection.Open();
|
||||
using NpgsqlCommand npgsqlCommand = new(commandText, npgsqlConnection);
|
||||
npgsqlCommand.Parameters.AddRange(npgsqlParameters.ToArray());
|
||||
NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.SequentialAccess);
|
||||
while (npgsqlDataReader.Read())
|
||||
_ = stringBuilder.Append(npgsqlDataReader.GetString(0));
|
||||
return stringBuilder;
|
||||
while (npgsqlDataReader.Read()) {
|
||||
_ = result.Append(npgsqlDataReader.GetString(0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<Asset>? Get()
|
||||
{
|
||||
string commandText = GetCommandText();
|
||||
if (commandText.Length == 1)
|
||||
{
|
||||
int? result = ExecuteNonQuery(_AppSettings.ConnectionString, commandText);
|
||||
if (result is null)
|
||||
{ }
|
||||
public string? GetColumns() {
|
||||
string result;
|
||||
NpgsqlParameter[] npgsqlParameters = [];
|
||||
string commandText = CommandText.GetColumns();
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetOwnerIds() {
|
||||
string result;
|
||||
NpgsqlParameter[] npgsqlParameters = [];
|
||||
string commandText = CommandText.GetOwnerIdActiveImage(_Settings.LowestVersionHistory);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? GetAssets(Guid ownerId) {
|
||||
string result;
|
||||
ReadOnlyCollection<string> people = Array.Empty<string>().AsReadOnly();
|
||||
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
|
||||
string commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people);
|
||||
StringBuilder stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
result = stringBuilder.ToString();
|
||||
if (result.Length == 1) {
|
||||
File.WriteAllText(".vscode/jsonl/assets.jsonl", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<string>? GetRandomPaths(Guid ownerId, string? monthDay) {
|
||||
string[]? results;
|
||||
string commandText;
|
||||
Random random = new();
|
||||
List<string> people = [];
|
||||
StringBuilder stringBuilder;
|
||||
if (!string.IsNullOrEmpty(monthDay)) {
|
||||
foreach (KeyValuePair<string, string> keyValuePair in _Settings.People) {
|
||||
if (!keyValuePair.Key.Contains(monthDay)) {
|
||||
continue;
|
||||
}
|
||||
people.Add($"People/{keyValuePair.Value.Trim('/')}");
|
||||
}
|
||||
}
|
||||
try {
|
||||
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
|
||||
commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people.AsReadOnly());
|
||||
stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
} catch (Exception) {
|
||||
people.Clear();
|
||||
NpgsqlParameter[] npgsqlParameters = [new NpgsqlParameter(nameof(ownerId), ownerId)];
|
||||
commandText = CommandText.GetAssetActiveImagePreviewNotDuplicate(_Settings.LowestVersionHistory, _Settings.FilterTags.AsReadOnly(), people.AsReadOnly());
|
||||
stringBuilder = GetForJsonPath(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
}
|
||||
StringBuilder stringBuilder = GetForJsonPath(_AppSettings.ConnectionString, commandText);
|
||||
if (commandText.Length == 1)
|
||||
File.WriteAllText(".vscode/jsonl/.jsonl", stringBuilder.ToString());
|
||||
string json = stringBuilder.ToString();
|
||||
string ownerIdValue = ownerId.ToString();
|
||||
Asset[]? assets = JsonSerializer.Deserialize(json, AssetCollectionSourceGenerationContext.Default.AssetArray);
|
||||
return assets?.AsReadOnly();
|
||||
results = assets is null ? null : (from l in assets orderby random.NextSingle() select l.Path.Split(ownerIdValue)[1]).ToArray();
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
// 1. fetch user
|
||||
// 1. fetch asset
|
||||
// 1. check wether the user reached the
|
||||
// 1. update the user
|
||||
// 1. save the asset
|
||||
public void Create(Asset asset)
|
||||
{
|
||||
// Guid userId,
|
||||
if (asset is null)
|
||||
throw new ArgumentNullException(nameof(asset));
|
||||
|
||||
// User user = _UsersRepository.Find(x => x.Id == userId)
|
||||
// ?? throw new InvalidOperationException();
|
||||
|
||||
// user.AddAsset(asset);
|
||||
_AssetsRepository.Add(asset);
|
||||
public Tag[]? GetArchivedTag(Settings settings, Guid ownerId) {
|
||||
Tag[]? results;
|
||||
Guid userId = ownerId;
|
||||
string value = settings.ArchivedTag;
|
||||
NpgsqlParameter[] npgsqlParameters = [
|
||||
new NpgsqlParameter(nameof(value), value),
|
||||
new NpgsqlParameter(nameof(userId), userId),
|
||||
];
|
||||
string commandText = CommandText.GetArchivedTag(_Settings.LowestVersionHistory);
|
||||
StringBuilder stringBuilder = GetForJsonPath(settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
string json = stringBuilder.ToString();
|
||||
results = JsonSerializer.Deserialize(json, TagCollectionSourceGenerationContext.Default.TagArray);
|
||||
return results;
|
||||
}
|
||||
|
||||
public Asset? Get(Guid assetId) =>
|
||||
_AssetsRepository.Find(l => l.Id == assetId.ToString());
|
||||
public string? GetArchivedTag(Guid ownerId) {
|
||||
string? result;
|
||||
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
|
||||
result = tags is null || tags.Length != 1 ? null : tags[0].Id;
|
||||
return result;
|
||||
}
|
||||
|
||||
public string? SaveRandomPaths(Guid ownerId, string? monthDay) {
|
||||
string? results = null;
|
||||
FileInfo fileInfo;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
ReadOnlyCollection<string>? paths;
|
||||
bool? check = monthDay is null ? null : monthDay == "00-00";
|
||||
if (Directory.Exists(_Settings.RandomResultsDirectory)) {
|
||||
_ = Directory.CreateDirectory(_Settings.RandomResultsDirectory);
|
||||
}
|
||||
for (int i = 0; i < 366; i++) {
|
||||
if (check is null || check.Value) {
|
||||
monthDay = i == 0 && check is not null && check.Value ? "02-29" : dateTime.AddDays(i).ToString("MM-dd");
|
||||
}
|
||||
fileInfo = new(Path.Combine(_Settings.RandomResultsDirectory, $"{monthDay}.json"));
|
||||
if (fileInfo.Exists && fileInfo.CreationTime > dateTime.AddDays(_Settings.AddDays)) {
|
||||
results = null;
|
||||
} else {
|
||||
_Logger.LogDebug("Writing <{FullName}>", fileInfo.FullName);
|
||||
paths = GetRandomPaths(ownerId, monthDay);
|
||||
if (paths is null) {
|
||||
results = null;
|
||||
} else {
|
||||
_Logger.LogInformation("{count} path(s)", paths.Count.ToString());
|
||||
results = JsonSerializer.Serialize(paths);
|
||||
File.WriteAllText(fileInfo.FullName, results);
|
||||
}
|
||||
}
|
||||
if (check is null || !check.Value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private record Record(string Source, string Destination);
|
||||
|
||||
public ReadOnlyCollection<string> SyncImmich(Guid ownerId) {
|
||||
List<string> results = [];
|
||||
Record record;
|
||||
List<Record> records = [];
|
||||
if (Directory.Exists(_Settings.SyncDirectory)) {
|
||||
_ = Directory.CreateDirectory(_Settings.SyncDirectory);
|
||||
}
|
||||
int syncLength = _Settings.SyncDirectory.Length;
|
||||
string[] syncFiles = Directory.GetFiles(_Settings.SyncDirectory, "*", SearchOption.AllDirectories);
|
||||
string[] syncCheck = syncFiles.Select(l => l[syncLength..]).ToArray();
|
||||
if (Directory.Exists(_Settings.ImmichUploadDirectory)) {
|
||||
_ = Directory.CreateDirectory(_Settings.ImmichUploadDirectory);
|
||||
}
|
||||
int immichUploadLength = _Settings.ImmichUploadDirectory.Length;
|
||||
string[] immichUploadFiles = Directory.GetFiles(_Settings.ImmichUploadDirectory, "*", SearchOption.AllDirectories);
|
||||
string[] immichUploadCheck = immichUploadFiles.Select(l => l[immichUploadLength..]).ToArray();
|
||||
for (int i = 0; i < immichUploadFiles.Length; i++) {
|
||||
if (syncCheck.Contains(immichUploadCheck[i])) {
|
||||
continue;
|
||||
}
|
||||
results.Add(immichUploadCheck[i]);
|
||||
record = new(immichUploadFiles[i], string.Concat(_Settings.SyncDirectory, immichUploadCheck[i]));
|
||||
records.Add(record);
|
||||
}
|
||||
_Logger.LogInformation("{count} file(s)", results.Count.ToString());
|
||||
for (int i = 0; i < records.Count; i++) {
|
||||
record = records[i];
|
||||
_Logger.LogDebug("Copying <{source}>", record.Source);
|
||||
File.Copy(record.Source, record.Destination);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<int>? SetArchiveImmich(Guid ownerId) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
if (!File.Exists(_Settings.NotNinePath)) {
|
||||
results = null;
|
||||
} else {
|
||||
string json = File.ReadAllText(_Settings.NotNinePath);
|
||||
Identifier[]? identifiers = JsonSerializer.Deserialize<Identifier[]>(json);
|
||||
if (identifiers is null || identifiers.Length == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
|
||||
if (tags is null || tags.Length != 1) {
|
||||
results = null;
|
||||
} else {
|
||||
results = SetArchiveImmich(logger, _Settings, ownerId, identifiers.AsReadOnly(), tags.AsReadOnly());
|
||||
}
|
||||
}
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, string tagsId, string deviceAssetIds) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
NpgsqlParameter[] npgsqlParameters = [
|
||||
new NpgsqlParameter(nameof(tagsId), tagsId),
|
||||
new NpgsqlParameter(nameof(ownerId), ownerId),
|
||||
];
|
||||
string commandText = CommandText.SetAssetArchived(settings.LowestVersionHistory, deviceAssetIds);
|
||||
logger.LogDebug(commandText.Replace($"@{nameof(tagsId)}", $"'{tagsId}'").Replace($"@{nameof(ownerId)}", $"'{ownerId}'".ToString()));
|
||||
int? result = ExecuteNonQuery(settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
results = result is null ? null : new([result.Value]);
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, ReadOnlyCollection<Identifier> identifiers, ReadOnlyCollection<Tag> tags) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
string tagsId = tags[0].Id;
|
||||
string deviceAssetIds = Identifier.GetDeviceAssetIds(identifiers);
|
||||
results = SetArchiveImmich(logger, settings, ownerId, tagsId, deviceAssetIds);
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<int>? SetDigiKam4ArchiveImmich(Guid ownerId) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
ReadOnlyCollection<ImageTag>? imageTags = ImageTag.Get(tag: _Settings.ArchivedTag,
|
||||
tagsPath: _Settings.DigiKam4?.Tags,
|
||||
imageTagsPath: _Settings.DigiKam4?.ImageTags,
|
||||
imagesPath: _Settings.DigiKam4?.Images);
|
||||
if (imageTags is null || imageTags.Count == 0) {
|
||||
results = null;
|
||||
} else {
|
||||
Tag[]? tags = GetArchivedTag(_Settings, ownerId);
|
||||
if (tags is null || tags.Length != 1) {
|
||||
results = null;
|
||||
} else {
|
||||
results = SetArchiveImmich(logger, _Settings, ownerId, imageTags, tags.AsReadOnly());
|
||||
}
|
||||
}
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<int>? SetArchiveImmich(ILogger<Program> logger, Settings settings, Guid ownerId, ReadOnlyCollection<ImageTag> imageTags, ReadOnlyCollection<Tag> tags) {
|
||||
ReadOnlyCollection<int>? results;
|
||||
string tagsId = tags[0].Id;
|
||||
string deviceAssetIds = Identifier.GetDeviceAssetIds(imageTags);
|
||||
results = SetArchiveImmich(logger, settings, ownerId, tagsId, deviceAssetIds);
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<int>? UpdateAssetsSetLocalDateTimeForThreeAndSeven() {
|
||||
ReadOnlyCollection<int>? results;
|
||||
NpgsqlParameter[] npgsqlParameters = [];
|
||||
string commandText = CommandText.UpdateAssetsSetLocalDateTimeForThreeAndSeven(_Settings.LowestVersionHistory);
|
||||
int? result = ExecuteNonQuery(_Settings.ConnectionString, commandText, npgsqlParameters.AsReadOnly());
|
||||
results = result is null ? null : new([result.Value]);
|
||||
return results?.AsReadOnly();
|
||||
}
|
||||
|
||||
}
|
218
src/ImmichToSlideshow/Services/CommandText.cs
Normal file
218
src/ImmichToSlideshow/Services/CommandText.cs
Normal file
@ -0,0 +1,218 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace ImmichToSlideshow.Services;
|
||||
|
||||
internal static class CommandText {
|
||||
|
||||
internal static string GetColumns() { // cSpell:disable
|
||||
List<string> results = [
|
||||
// " SELECT COALESCE(SUM(checksum_failures), 0) ",
|
||||
// " FROM pg_stat_database ",
|
||||
// " SELECT json_agg(t) ",
|
||||
// " FROM information_schema.tables t ",
|
||||
// " WHERE table_schema= 'public' ",
|
||||
// " AND table_type= 'BASE TABLE' ",
|
||||
" SELECT json_agg(c) ",
|
||||
" FROM information_schema.columns c ",
|
||||
// " WHERE table_name = 'assets' ",
|
||||
// " WHERE table_name = 'libraries' ",
|
||||
" WHERE table_name = 'asset_files'; "
|
||||
];
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
internal static string GetOwnerIdActiveImage(float lowestVersionHistory) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(j) ",
|
||||
" FROM ( ",
|
||||
" SELECT a.\"ownerId\" "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE a.\"status\" = 'active' ",
|
||||
" AND a.\"type\" = 'IMAGE' ",
|
||||
" GROUP",
|
||||
" BY a.\"ownerId\" ",
|
||||
" ) j; "
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
internal static string GetAssetActiveImagePreviewNotDuplicate(float lowestVersionHistory, ReadOnlyCollection<string> filterTags, ReadOnlyCollection<string> people) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(j) ",
|
||||
" FROM ( ",
|
||||
" SELECT a.\"id\" ",
|
||||
" , a.\"deviceAssetId\" ",
|
||||
// " , a.\"ownerId\" ",
|
||||
// " , a.\"deviceId\" ",
|
||||
// " , a.\"type\" ",
|
||||
" , a.\"originalPath\" ",
|
||||
// " , a.\"fileCreatedAt\" ",
|
||||
// " , a.\"fileModifiedAt\" ",
|
||||
// " , a.\"isFavorite\" ",
|
||||
// " , a.\"duration\" ",
|
||||
// " , a.\"encodedVideoPath\" ",
|
||||
// " , a.\"checksum\" ",
|
||||
// " , a.\"isVisible\" ",
|
||||
// " , a.\"livePhotoVideoId\" ",
|
||||
// " , a.\"updatedAt\" ",
|
||||
// " , a.\"createdAt\" ",
|
||||
// " , a.\"isArchived\" ",
|
||||
" , a.\"originalFileName\" ",
|
||||
// " , a.\"sidecarPath\" ",
|
||||
// " , a.\"thumbhash\" ",
|
||||
// " , a.\"isOffline\" ",
|
||||
// " , a.\"libraryId\" ",
|
||||
// " , a.\"isExternal\" ",
|
||||
// " , a.\"deletedAt\" ",
|
||||
// " , a.\"localDateTime\" ",
|
||||
// " , a.\"stackId\" ",
|
||||
" , a.\"duplicateId\" ",
|
||||
// " , a.\"status\" ",
|
||||
" , f.\"path\" "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.Add(" INNER ");
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN asset_files f ");
|
||||
} else {
|
||||
results.Add(" JOIN public.asset_file f ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON a.\"id\" = f.\"assetId\" ",
|
||||
" WHERE a.\"status\" = 'active' ",
|
||||
" AND a.\"type\" = 'IMAGE' ",
|
||||
" AND f.\"type\" = 'preview' ",
|
||||
" AND a.\"duplicateId\" is null ",
|
||||
" AND a.\"id\" not in ( ",
|
||||
" SELECT \"assetsId\" "
|
||||
]);
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM tag_asset g ");
|
||||
} else {
|
||||
results.Add(" FROM public.tag_asset g ");
|
||||
}
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN tags t ");
|
||||
} else {
|
||||
results.Add(" JOIN public.tag t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON g.\"tagsId\" = t.\"id\" ",
|
||||
$" WHERE t.\"value\" in ('{string.Join("','", filterTags)}') ",
|
||||
" ) "]);
|
||||
if (people.Count > 0) {
|
||||
results.AddRange([
|
||||
" AND a.\"id\" in ( ",
|
||||
" SELECT \"assetsId\" "
|
||||
]);
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM tag_asset g ");
|
||||
} else {
|
||||
results.Add(" FROM public.tag_asset g ");
|
||||
}
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN tags t ");
|
||||
} else {
|
||||
results.Add(" JOIN public.tag t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON g.\"tagsId\" = t.\"id\" ",
|
||||
$" WHERE t.\"value\" in ('{string.Join("','", people)}') ",
|
||||
" ) "]);
|
||||
}
|
||||
results.AddRange([
|
||||
" AND a.\"isExternal\" = true ",
|
||||
" AND a.\"isOffline\" = false ",
|
||||
" AND a.\"ownerId\" = @ownerId ",
|
||||
" ) j; "
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
internal static string SetAssetArchived(float lowestVersionHistory, string deviceAssetIds) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" INSERT INTO tag_asset ",
|
||||
" (\"assetsId\", \"tagsId\") ",
|
||||
" SELECT a.\"id\", @tagsId::uuid "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets a ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset a ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE a.\"type\" = 'IMAGE' ",
|
||||
" AND a.\"ownerId\" = @ownerId ",
|
||||
" AND a.\"deviceAssetId\" in ( ",
|
||||
deviceAssetIds,
|
||||
" ) ",
|
||||
" AND a.\"id\" not in ( ",
|
||||
" SELECT \"id\" "
|
||||
]);
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM assets b ");
|
||||
} else {
|
||||
results.Add(" FROM public.asset b ");
|
||||
}
|
||||
results.Add(" INNER ");
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" JOIN tag_asset t ");
|
||||
} else {
|
||||
results.Add(" JOIN public.tag_asset t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" ON b.\"id\" = t.\"assetsId\" ",
|
||||
" WHERE t.\"tagsId\" = @tagsId::uuid ",
|
||||
" AND b.\"deviceAssetId\" in ( ",
|
||||
deviceAssetIds,
|
||||
" ) ",
|
||||
" ); "
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
internal static string GetArchivedTag(float lowestVersionHistory) { // cSpell:disable
|
||||
List<string> results = [
|
||||
" SELECT json_agg(t) "
|
||||
];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" FROM tags t ");
|
||||
} else {
|
||||
results.Add(" FROM public.tag t ");
|
||||
}
|
||||
results.AddRange([
|
||||
" WHERE t.\"value\" = @value ",
|
||||
" AND t.\"userId\" = @userId; "
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
internal static string UpdateAssetsSetLocalDateTimeForThreeAndSeven(float lowestVersionHistory) { // cSpell:disable
|
||||
List<string> results = [];
|
||||
if (lowestVersionHistory <= 1.129) {
|
||||
results.Add(" UPDATE assets ");
|
||||
} else {
|
||||
results.Add(" UPDATE public.asset ");
|
||||
}
|
||||
results.AddRange([
|
||||
" SET \"localDateTime\" = TIMESTAMPTZ(\"localDateTime\") - INTERVAL '100 years' ",
|
||||
" WHERE \"localDateTime\" > TIMESTAMPTZ '1990-01-01 00:00:00-00' ",
|
||||
" AND ( ",
|
||||
" \"deviceAssetId\" like '%3.%' ",
|
||||
" OR \"deviceAssetId\" like '%7.%' ",
|
||||
" ); ",
|
||||
]);
|
||||
return string.Join(Environment.NewLine, results);
|
||||
} // cSpell:enable
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
Reference in New Issue
Block a user