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