admin.html (18669B)
1 {{template "_header" .}} 2 <h1>Admin</h1> 3 4 {{if .Data.Error}} 5 <div style="background-color: #f8d7da; color: #721c24; padding: 10px; border: 1px solid #f5c6cb; border-radius: 4px; margin-bottom: 20px;"> 6 <strong>Error:</strong> {{.Data.Error}} 7 </div> 8 {{end}} 9 10 {{if .Data.Success}} 11 <div style="background-color: #d4edda; color: #155724; padding: 10px; border: 1px solid #c3e6cb; border-radius: 4px; margin-bottom: 20px;"> 12 <strong>Success:</strong> {{.Data.Success}} 13 </div> 14 {{end}} 15 16 <!-- Tab Navigation --> 17 <div style="margin-bottom: 20px; border-bottom: 2px solid #ddd;"> 18 <button onclick="showAdminTab('settings')" id="admin-tab-settings" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid #007bff; font-weight: bold;"> 19 Settings 20 </button> 21 <button onclick="showAdminTab('database')" id="admin-tab-database" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 22 Database 23 </button> 24 <button onclick="showAdminTab('aliases')" id="admin-tab-aliases" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 25 Aliases 26 </button> 27 <button onclick="showAdminTab('sedrules')" id="admin-tab-sedrules" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 28 Sed Rules 29 </button> 30 <button onclick="showAdminTab('orphans')" id="admin-tab-orphans" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 31 Orphans 32 </button> 33 <button onclick="showAdminTab('thumbnails')" id="admin-tab-thumbnails" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 34 Thumbnails 35 </button> 36 </div> 37 38 <!-- Settings Tab --> 39 <div id="admin-content-settings"> 40 <div class="config-container"> 41 <div class="config-split"> 42 <h2>Settings</h2> 43 <form method="post" style="max-width: 600px;"> 44 <input type="hidden" name="active_tab" value="settings"> 45 <div style="margin-bottom: 20px;"> 46 <label for="database_path" style="display: block; font-weight: bold; margin-bottom: 5px;">Database Path:</label> 47 <input type="text" id="database_path" name="database_path" value="{{.Data.Config.DatabasePath}}" required 48 style="width: 100%; padding: 8px; font-size: 14px;" 49 placeholder="./database.db"> 50 <small style="color: #666;">Path to SQLite database file (requires restart if changed)</small> 51 </div> 52 53 <div style="margin-bottom: 20px;"> 54 <label for="upload_dir" style="display: block; font-weight: bold; margin-bottom: 5px;">Upload Directory:</label> 55 <input type="text" id="upload_dir" name="upload_dir" value="{{.Data.Config.UploadDir}}" required 56 style="width: 100%; padding: 8px; font-size: 14px;" 57 placeholder="uploads"> 58 <small style="color: #666;">Directory where uploaded files are stored</small> 59 </div> 60 61 <div style="margin-bottom: 20px;"> 62 <label for="server_port" style="display: block; font-weight: bold; margin-bottom: 5px;">Server Port:</label> 63 <input type="text" id="server_port" name="server_port" value="{{.Data.Config.ServerPort}}" required 64 style="width: 100%; padding: 8px; font-size: 14px;" 65 placeholder=":8080"> 66 <small style="color: #666;">Port for web server (format: :8080, requires restart if changed)</small> 67 </div> 68 69 <div style="margin-bottom: 20px;"> 70 <label for="gallery_size" style="display: block; font-weight: bold; margin-bottom: 5px;">Gallery Size:</label> 71 <input type="text" id="gallery_size" name="gallery_size" value="{{.Data.Config.GallerySize}}" required 72 style="width: 100%; padding: 8px; font-size: 14px;" 73 placeholder="400px"> 74 <small style="color: #666;">Size of previews used in galleries</small> 75 </div> 76 77 <div style="margin-bottom: 20px;"> 78 <label for="items_per_page" style="display: block; font-weight: bold; margin-bottom: 5px;">Items per Page:</label> 79 <input type="text" id="items_per_page" name="items_per_page" value="{{.Data.Config.ItemsPerPage}}" required 80 style="width: 100%; padding: 8px; font-size: 14px;" 81 placeholder="100"> 82 <small style="color: #666;">Items per page in galleries</small> 83 </div> 84 85 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 86 Save Settings 87 </button> 88 </form> 89 </div> 90 91 <div class="config-split"> 92 <h3>Current Configuration:</h3> 93 <ul> 94 <li><strong>Database:</strong> {{.Data.Config.DatabasePath}}</li> 95 <li><strong>Upload Directory:</strong> {{.Data.Config.UploadDir}}</li> 96 <li><strong>Server Port:</strong> {{.Data.Config.ServerPort}}</li> 97 <li><strong>Gallery Size:</strong> {{.Data.Config.GallerySize}}</li> 98 <li><strong>Items per Page:</strong> {{.Data.Config.ItemsPerPage}}</li> 99 </ul> 100 101 <h4>Configuration File:</h4> 102 <p>Settings are stored in <code>config.json</code> in the application directory.</p> 103 </div> 104 </div> 105 </div> 106 107 <!-- Database Tab --> 108 <div id="admin-content-database" style="display: none;"> 109 <h2>Database Maintenance</h2> 110 111 <form method="post" style="margin-bottom: 20px;"> 112 <input type="hidden" name="active_tab" value="database"> 113 <input type="hidden" name="action" value="backup"> 114 <button type="submit" style="background-color: #28a745; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 115 Backup Database 116 </button> 117 <small style="color: #666; margin-left: 10px;">Creates a timestamped backup of the database file</small> 118 </form> 119 120 <form method="post"> 121 <input type="hidden" name="active_tab" value="database"> 122 <input type="hidden" name="action" value="vacuum"> 123 <button type="submit" style="background-color: #6f42c1; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 124 Vacuum Database 125 </button> 126 <small style="color: #666; margin-left: 10px;">Reclaims unused space and optimizes database performance</small> 127 </form> 128 129 <hr style="margin: 30px 0; border: none; border-top: 1px solid #ddd;"> 130 <h3>File Properties</h3> 131 <p style="color: #666; margin-bottom: 10px;"> 132 Compute auto-detected properties (filetype, duration, orientation, resolution) for any files that do not yet have them. 133 </p> 134 <form method="post"> 135 <input type="hidden" name="active_tab" value="database"> 136 <input type="hidden" name="action" value="compute_properties"> 137 <button type="submit" style="background-color: #17a2b8; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 138 Compute Missing Properties 139 </button> 140 <small style="color: #666; margin-left: 10px;">Processes only files with no existing properties</small> 141 </form> 142 </div> 143 144 <!-- Aliases Tab --> 145 <div id="admin-content-aliases" style="display: none;"> 146 <h2>Tag Aliases</h2> 147 <p> 148 Define tag aliases so that multiple tag values are treated as equivalent when searching or filtering. 149 For example, if you alias "colour/blue" with "colour/navy", searching for either will show files tagged with both. 150 </p> 151 152 <div id="aliases-section" style="max-width: 800px;"> 153 <div id="alias-groups"></div> 154 155 <button onclick="addAliasGroup()" style="background-color: #28a745; color: white; padding: 8px 16px; border: none; border-radius: 4px; font-size: 14px; cursor: pointer; margin-top: 10px;"> 156 + Add Alias Group 157 </button> 158 159 <form method="post" id="aliases-form" style="margin-top: 20px;"> 160 <input type="hidden" name="active_tab" value="aliases"> 161 <input type="hidden" name="action" value="save_aliases"> 162 <input type="hidden" name="aliases_json" id="aliases_json"> 163 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 164 Save Aliases 165 </button> 166 </form> 167 </div> 168 </div> 169 170 <!-- Sed Rules Tab --> 171 <div id="admin-content-sedrules" style="display: none;"> 172 <div class="config-container"> 173 <div class="config-split"> 174 <h2>Sed Rules for Notes</h2> 175 <p> 176 Define sed rules that can be applied to notes in the Notes editor. 177 These rules will appear as buttons in the notes interface for quick text transformations. 178 </p> 179 180 <div id="sedrules-section" style="max-width: 800px;"> 181 <div id="sed-rules"></div> 182 183 <button onclick="addSedRule()" style="background-color: #28a745; color: white; padding: 8px 16px; border: none; border-radius: 4px; font-size: 14px; cursor: pointer; margin-top: 10px;"> 184 + Add Sed Rule 185 </button> 186 187 <form method="post" action="/admin" id="sedrules-form" style="margin-top: 20px;"> 188 <input type="hidden" name="active_tab" value="sedrules"> 189 <input type="hidden" name="action" value="save_sed_rules"> 190 <input type="hidden" name="sed_rules_json" id="sed_rules_json"> 191 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 192 Save Sed Rules 193 </button> 194 </form> 195 </div> 196 </div> 197 198 <div class="config-split"> 199 <h4 style="margin-top: 0;">Example Sed Commands:</h4> 200 <ul style="font-family: monospace; font-size: 13px;"> 201 <li><code>s?[?&]brandIds=[0-9]\+&productId=[0-9]\+??g</code> - Remove URL parameters</li> 202 <li><code>s/[[:space:]]*$//</code> - Remove trailing whitespace</li> 203 <li><code>s/ \+/ /g</code> - Replace multiple spaces with single space</li> 204 <li><code>s/https\?:\/\/[^ ]*//g</code> - Remove URLs</li> 205 <li><code>/^$/d</code> - Delete empty lines</li> 206 </ul> 207 </div> 208 </div> 209 </div> 210 211 <!-- Orphans Tab --> 212 <div id="admin-content-orphans" style="display: none;"> 213 <h2>Orphaned Files</h2> 214 215 <!-- Files on disk, not in DB --> 216 <h3 style="margin-top: 24px;">Disk Orphans</h3> 217 <p style="color: #666; margin-bottom: 12px;"> 218 These files exist in the upload directory but are not tracked in the database. 219 </p> 220 {{if .Data.OrphanData.Orphans}} 221 <ul style="list-style-type: disc; padding-left: 20px;"> 222 {{range .Data.OrphanData.Orphans}} 223 <li style="margin-bottom: 5px; font-family: monospace;">{{.}}</li> 224 {{end}} 225 </ul> 226 {{else}} 227 <div style="padding: 20px; background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"> 228 <strong>✓ No disk orphans found!</strong> 229 </div> 230 {{end}} 231 232 <!-- Files in DB, not on disk --> 233 <h3 style="margin-top: 32px;">Database Orphans</h3> 234 <p style="color: #666; margin-bottom: 12px;"> 235 These files are tracked in the database but are missing from the upload directory. 236 </p> 237 {{if .Data.OrphanData.ReverseOrphans}} 238 <ul style="list-style-type: disc; padding-left: 20px;"> 239 {{range .Data.OrphanData.ReverseOrphans}} 240 <li style="margin-bottom: 5px; font-family: monospace;">{{.}}</li> 241 {{end}} 242 </ul> 243 {{else}} 244 <div style="padding: 20px; background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"> 245 <strong>✓ No database orphans found!</strong> 246 </div> 247 {{end}} 248 </div> 249 250 <!-- Thumbnails Tab --> 251 <div id="admin-content-thumbnails" style="display: none;"> 252 <h2>Thumbnail Management</h2> 253 254 <!-- Sub-tab Navigation --> 255 <div style="margin-bottom: 20px; border-bottom: 1px solid #ddd;"> 256 <button onclick="showThumbnailSubTab('missing')" id="thumb-subtab-missing" class="thumb-subtab-btn" style="padding: 8px 16px; border: none; background: none; cursor: pointer; border-bottom: 2px solid #007bff; font-weight: bold;"> 257 Missing ({{len .Data.MissingThumbnails}}) 258 </button> 259 <button onclick="showThumbnailSubTab('regenerate')" id="thumb-subtab-regenerate" class="thumb-subtab-btn" style="padding: 8px 16px; border: none; background: none; cursor: pointer; border-bottom: 2px solid transparent;"> 260 Regenerate 261 </button> 262 </div> 263 264 <!-- Missing Thumbnails Sub-tab --> 265 <div id="thumb-content-missing"> 266 <h3>Missing Thumbnails ({{len .Data.MissingThumbnails}})</h3> 267 268 {{if .Data.MissingThumbnails}} 269 <form method="post" action="/thumbnails/generate" style="margin-bottom: 20px;"> 270 <input type="hidden" name="action" value="generate_all"> 271 <button type="submit" onclick="return confirm('Generate thumbnails for all {{len .Data.MissingThumbnails}} videos? This may take a while.');" style="background-color: #28a745; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 272 Generate All Missing Thumbnails 273 </button> 274 <small style="color: #666; margin-left: 10px;">Uses timestamp 00:00:05 for all videos</small> 275 </form> 276 277 <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;"> 278 {{range .Data.MissingThumbnails}} 279 <div style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; background-color: #f8f9fa;"> 280 <h4 style="margin-top: 0; font-size: 14px; word-break: break-word;"> 281 <a href="/file/{{.ID}}" target="_blank">{{.Filename}}</a> 282 </h4> 283 <p style="color: #666; font-size: 12px; margin: 5px 0;">ID: {{.ID}}</p> 284 285 <video width="100%" style="max-height: 200px; background: #000; margin: 10px 0; cursor: pointer;" title="Click to capture frame"> 286 <source src="/uploads/{{.EscapedFilename}}"> 287 </video> 288 289 <form method="post" action="/thumbnails/generate" style="margin-top: 10px;"> 290 <input type="hidden" name="action" value="generate_single"> 291 <input type="hidden" name="file_id" value="{{.ID}}"> 292 <input type="hidden" name="redirect" value="admin"> 293 294 <div style="display: flex; gap: 5px; align-items: center; margin-bottom: 10px;"> 295 <label style="font-size: 13px; white-space: nowrap;">Timestamp:</label> 296 <input type="text" name="timestamp" value="00:00:05" placeholder="00:00:05" 297 style="flex: 1; padding: 5px; font-size: 13px; font-family: monospace;"> 298 </div> 299 300 <button type="submit" style="background-color: #007bff; color: white; padding: 6px 12px; border: none; border-radius: 3px; font-size: 13px; cursor: pointer; width: 100%;"> 301 Generate Thumbnail 302 </button> 303 </form> 304 </div> 305 {{end}} 306 </div> 307 {{else}} 308 <div style="padding: 20px; background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"> 309 <strong>✓ All videos have thumbnails!</strong> 310 </div> 311 {{end}} 312 </div> 313 314 <!-- Regenerate Sub-tab --> 315 <div id="thumb-content-regenerate" style="display: none;"> 316 <h3>Regenerate Thumbnail</h3> 317 318 <div style="margin-bottom: 20px; padding: 10px; background-color: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 4px;"> 319 <strong>Tip:</strong> Enter a file ID to regenerate its thumbnail with a custom timestamp. You can find file IDs in the URL when viewing a file (e.g., /file/312). 320 </div> 321 322 <form method="post" action="/thumbnails/generate" style="max-width: 500px; padding: 20px; background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 5px;"> 323 <input type="hidden" name="action" value="generate_single"> 324 <input type="hidden" name="redirect" value="admin"> 325 326 <div style="margin-bottom: 20px;"> 327 <label for="file_id" style="display: block; font-weight: bold; margin-bottom: 5px;">File ID:</label> 328 <input type="text" id="file_id" name="file_id" required 329 style="width: 100%; padding: 8px; font-size: 14px; font-family: monospace;" 330 placeholder="e.g., 312"> 331 <small style="color: #666;">Enter the ID of the video file</small> 332 </div> 333 334 <div style="margin-bottom: 20px;"> 335 <label for="timestamp" style="display: block; font-weight: bold; margin-bottom: 5px;">Timestamp:</label> 336 <input type="text" id="timestamp" name="timestamp" value="00:00:05" required 337 style="width: 100%; padding: 8px; font-size: 14px; font-family: monospace;" 338 placeholder="00:00:05"> 339 <small style="color: #666;">Format: HH:MM:SS (e.g., 00:00:05 for 5 seconds)</small> 340 </div> 341 342 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; width: 100%;"> 343 Generate/Regenerate Thumbnail 344 </button> 345 </form> 346 </div> 347 </div> 348 349 <script>window.initialAliasGroups = {{.Data.Config.TagAliases}};</script> 350 <script>window.initialSedRules = {{.Data.Config.SedRules}};</script> 351 <script>window.activeAdminTab = "{{.Data.ActiveTab}}";</script> 352 <script src="/static/tag-alias.js" defer></script> 353 <script src="/static/sed-rules.js" defer></script> 354 <script src="/static/admin-tabs.js" defer></script> 355 <script src="/static/common.js" defer></script> 356 357 {{template "_footer"}}