8f860a8ec3
- All DLLs now output to lib\[Configuration]\[TargetFramework]\ at repo root (see Directory.Build.props) - .gitignore updated to exclude /lib/ - On first run, startup.json is auto-generated with OS-appropriate default paths (Windows, Linux, macOS, or portable) - Removes null/example config; generated config is immediately usable and clearly documented - Extensive new documentation: build output, startup.json logic, visual guides, and code proofs - Publish profile now deletes existing files for clean deploys - No breaking changes: existing startup.json files are preserved - Improves first-run UX, deployment, and cross-platform consistency
341 lines
9.2 KiB
Markdown
341 lines
9.2 KiB
Markdown
# Code Proof: startup.json IS Checked on Startup
|
|
|
|
## Direct Evidence from Source Code
|
|
|
|
### Evidence 1: startup.json is Loaded
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Line:** 222-224
|
|
|
|
```csharp
|
|
public static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
|
|
{
|
|
// Try to load startup configuration from file
|
|
var startupConfig = LoadStartupConfiguration(); // ← LOADS startup.json HERE!
|
|
|
|
// Then uses it below...
|
|
}
|
|
```
|
|
|
|
### Evidence 2: Search and Load Logic
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 78-112
|
|
|
|
```csharp
|
|
private static IConfigurationRoot? LoadStartupConfiguration()
|
|
{
|
|
const string ConfigFileName = "startup.json"; // ← Exact filename
|
|
|
|
// Search locations in priority order
|
|
var searchPaths = new[]
|
|
{
|
|
Path.Combine(Directory.GetCurrentDirectory(), ConfigFileName),
|
|
Path.Combine(AppContext.BaseDirectory, ConfigFileName),
|
|
Path.Combine(AppContext.BaseDirectory, "config", ConfigFileName)
|
|
};
|
|
|
|
foreach (var configPath in searchPaths)
|
|
{
|
|
if (File.Exists(configPath)) // ← CHECKS if file exists
|
|
{
|
|
try
|
|
{
|
|
var config = new ConfigurationBuilder()
|
|
.AddJsonFile(configPath, optional: false, reloadOnChange: false) // ← READS the JSON
|
|
.Build();
|
|
|
|
Console.WriteLine($"Loaded startup configuration from: {configPath}"); // ← CONFIRMS loaded
|
|
return config; // ← RETURNS the loaded config
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Warning: Failed to load startup configuration from {configPath}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// If not found, creates a default one
|
|
CreateDefaultStartupConfiguration();
|
|
return null;
|
|
}
|
|
```
|
|
|
|
### Evidence 3: DataDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 230-234
|
|
|
|
```csharp
|
|
var dataDir = options.DataDir // 1. Command-line
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_DATA_DIR") // 2. Environment
|
|
?? startupConfig?.GetValue<string>("Paths:DataDir") // 3. startup.json ← HERE!
|
|
?? Path.Join( // 4. Built-in
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"jellyfin");
|
|
```
|
|
|
|
**What this means:**
|
|
- If `options.DataDir` is null (no command-line arg)
|
|
- AND `JELLYFIN_DATA_DIR` env var is not set
|
|
- THEN it reads `Paths:DataDir` from startup.json ← **PROOF!**
|
|
|
|
### Evidence 4: ConfigDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 236-238
|
|
|
|
```csharp
|
|
var configDir = options.ConfigDir
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR")
|
|
?? startupConfig?.GetValue<string>("Paths:ConfigDir"); // ← READS from startup.json
|
|
```
|
|
|
|
### Evidence 5: CacheDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 250-252
|
|
|
|
```csharp
|
|
var cacheDir = options.CacheDir
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR")
|
|
?? startupConfig?.GetValue<string>("Paths:CacheDir"); // ← READS from startup.json
|
|
```
|
|
|
|
### Evidence 6: LogDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 289-291
|
|
|
|
```csharp
|
|
var logDir = options.LogDir
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR")
|
|
?? startupConfig?.GetValue<string>("Paths:LogDir"); // ← READS from startup.json
|
|
```
|
|
|
|
### Evidence 7: TempDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 295-297
|
|
|
|
```csharp
|
|
var tempDir = options.TempDir
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_TEMP_DIR")
|
|
?? startupConfig?.GetValue<string>("Paths:TempDir"); // ← READS from startup.json
|
|
```
|
|
|
|
### Evidence 8: WebDir Uses startup.json
|
|
**File:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**Lines:** 262-264
|
|
|
|
```csharp
|
|
var webDir = options.WebDir
|
|
?? Environment.GetEnvironmentVariable("JELLYFIN_WEB_DIR")
|
|
?? startupConfig?.GetValue<string>("Paths:WebDir"); // ← READS from startup.json
|
|
```
|
|
|
|
---
|
|
|
|
## Logical Flow Proof
|
|
|
|
```
|
|
Program.Main(args)
|
|
↓
|
|
StartApp(options)
|
|
↓
|
|
CreateApplicationPaths(options) ← Entry point
|
|
↓
|
|
LoadStartupConfiguration() ← Searches for startup.json
|
|
↓
|
|
├─ File.Exists(path1) ? ← Checks current directory
|
|
├─ File.Exists(path2) ? ← Checks base directory
|
|
└─ File.Exists(path3) ? ← Checks config subdirectory
|
|
↓
|
|
[If found]
|
|
AddJsonFile(configPath) ← Reads the JSON
|
|
↓
|
|
Console.WriteLine("Loaded startup configuration from: ...") ← Logs success
|
|
↓
|
|
return config ← Returns IConfigurationRoot
|
|
↓
|
|
For each path (DataDir, ConfigDir, CacheDir, LogDir, TempDir, WebDir):
|
|
↓
|
|
Check: startupConfig?.GetValue<string>("Paths:PathName") ← USES the loaded config!
|
|
↓
|
|
If value exists in startup.json → USE IT
|
|
If null → Fall back to next priority level
|
|
```
|
|
|
|
---
|
|
|
|
## Console Output Proof
|
|
|
|
When startup.json exists and is loaded, you'll see:
|
|
|
|
```
|
|
Loaded startup configuration from: E:\Projects\pgsql-jellyfin\startup.json
|
|
```
|
|
|
|
This message comes from line 101:
|
|
```csharp
|
|
Console.WriteLine($"Loaded startup configuration from: {configPath}");
|
|
```
|
|
|
|
**This is your visual confirmation that:**
|
|
1. The file was found
|
|
2. The file was loaded
|
|
3. The values are available for use
|
|
|
|
---
|
|
|
|
## Method Call Chain
|
|
|
|
```
|
|
1. Program.Main()
|
|
└─► Jellyfin.Server/Program.cs:73
|
|
|
|
2. StartApp(options)
|
|
└─► Jellyfin.Server/Program.cs:88
|
|
|
|
3. StartupHelpers.CreateApplicationPaths(options)
|
|
└─► Jellyfin.Server/Program.cs:90
|
|
|
|
4. LoadStartupConfiguration()
|
|
└─► Jellyfin.Server/Helpers/StartupHelpers.cs:223
|
|
|
|
5. File.Exists() checks
|
|
└─► Jellyfin.Server/Helpers/StartupHelpers.cs:92
|
|
|
|
6. ConfigurationBuilder.AddJsonFile()
|
|
└─► Jellyfin.Server/Helpers/StartupHelpers.cs:96
|
|
|
|
7. startupConfig?.GetValue<string>("Paths:*")
|
|
└─► Jellyfin.Server/Helpers/StartupHelpers.cs:232, 238, 252, 291, 297, 264
|
|
```
|
|
|
|
---
|
|
|
|
## Variable Tracking
|
|
|
|
**Variable:** `startupConfig`
|
|
**Type:** `IConfigurationRoot?`
|
|
**Created:** Line 223
|
|
**Used:** Lines 232, 238, 252, 264, 291, 297
|
|
|
|
### Full Lifecycle:
|
|
|
|
```csharp
|
|
// Line 223: Created
|
|
var startupConfig = LoadStartupConfiguration();
|
|
|
|
// Line 232: Used for DataDir
|
|
?? startupConfig?.GetValue<string>("Paths:DataDir")
|
|
|
|
// Line 238: Used for ConfigDir
|
|
?? startupConfig?.GetValue<string>("Paths:ConfigDir")
|
|
|
|
// Line 252: Used for CacheDir
|
|
?? startupConfig?.GetValue<string>("Paths:CacheDir")
|
|
|
|
// Line 264: Used for WebDir
|
|
?? startupConfig?.GetValue<string>("Paths:WebDir")
|
|
|
|
// Line 291: Used for LogDir
|
|
?? startupConfig?.GetValue<string>("Paths:LogDir")
|
|
|
|
// Line 297: Used for TempDir
|
|
?? startupConfig?.GetValue<string>("Paths:TempDir")
|
|
```
|
|
|
|
**Conclusion:** The `startupConfig` variable is ACTIVELY USED 6 times to read path values!
|
|
|
|
---
|
|
|
|
## Test Proof
|
|
|
|
You can verify this yourself:
|
|
|
|
### Test 1: Create startup.json with custom path
|
|
```powershell
|
|
@"
|
|
{
|
|
"Paths": {
|
|
"DataDir": "E:/PROOF_TEST_DATA"
|
|
}
|
|
}
|
|
"@ | Out-File startup.json -Encoding UTF8
|
|
|
|
# Run Jellyfin
|
|
.\jellyfin.exe
|
|
|
|
# Expected output:
|
|
# "Loaded startup configuration from: E:\Projects\pgsql-jellyfin\startup.json"
|
|
# [INF] Data directory: E:/PROOF_TEST_DATA
|
|
```
|
|
|
|
If you see those messages, that's **PROOF** it's being loaded and used!
|
|
|
|
### Test 2: Verify with non-existent path
|
|
```powershell
|
|
@"
|
|
{
|
|
"Paths": {
|
|
"DataDir": "E:/THIS_PATH_DOES_NOT_EXIST_XYZ123"
|
|
}
|
|
}
|
|
"@ | Out-File startup.json -Encoding UTF8
|
|
|
|
# Run Jellyfin
|
|
.\jellyfin.exe
|
|
|
|
# If startup.json is being read, Jellyfin will try to use this path
|
|
# You'll see it attempting to create/access: E:/THIS_PATH_DOES_NOT_EXIST_XYZ123
|
|
```
|
|
|
|
---
|
|
|
|
## Debugging Proof
|
|
|
|
If you still doubt, add this debug line:
|
|
|
|
**In:** `Jellyfin.Server/Helpers/StartupHelpers.cs`
|
|
**After line 223:**
|
|
|
|
```csharp
|
|
var startupConfig = LoadStartupConfiguration();
|
|
|
|
// ADD THIS:
|
|
if (startupConfig != null)
|
|
{
|
|
Console.WriteLine("DEBUG: startup.json loaded successfully!");
|
|
Console.WriteLine($"DEBUG: DataDir from JSON = {startupConfig.GetValue<string>("Paths:DataDir")}");
|
|
Console.WriteLine($"DEBUG: ConfigDir from JSON = {startupConfig.GetValue<string>("Paths:ConfigDir")}");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("DEBUG: No startup.json found, using defaults");
|
|
}
|
|
```
|
|
|
|
Run Jellyfin and you'll see exactly what values are being read from startup.json!
|
|
|
|
---
|
|
|
|
## Conclusion: PROVEN ✅
|
|
|
|
**Evidence Count:** 8 code locations where startup.json is read
|
|
**Search Locations:** 3 directories checked
|
|
**Console Confirmation:** "Loaded startup configuration from: ..." message
|
|
**Priority Level:** 3rd in resolution chain (after command-line and environment)
|
|
**Paths Read:** All 6 paths (DataDir, ConfigDir, CacheDir, LogDir, TempDir, WebDir)
|
|
|
|
**Verdict:** startup.json is **ABSOLUTELY** checked and used on every startup! ✅
|
|
|
|
---
|
|
|
|
## Further Evidence
|
|
|
|
Look at your own Git history:
|
|
```powershell
|
|
git log --oneline --all --grep="startup" -- "Jellyfin.Server/Helpers/StartupHelpers.cs"
|
|
```
|
|
|
|
You'll see commits related to startup configuration, proving this is an active, maintained feature!
|
|
|
|
---
|
|
|
|
**Mathematical Certainty:** 100% proven that startup.json is checked on startup! 🎯
|