admin.html (15054B)
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('orphans')" id="admin-tab-orphans" class="admin-tab-btn" style="padding: 10px 20px; border: none; background: none; cursor: pointer; border-bottom: 3px solid transparent;"> 28 Orphans 29 </button> 30 <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;"> 31 Thumbnails 32 </button> 33 </div> 34 35 <!-- Settings Tab --> 36 <div id="admin-content-settings"> 37 <h2>Settings</h2> 38 <form method="post" style="max-width: 600px;"> 39 <div style="margin-bottom: 20px;"> 40 <label for="database_path" style="display: block; font-weight: bold; margin-bottom: 5px;">Database Path:</label> 41 <input type="text" id="database_path" name="database_path" value="{{.Data.Config.DatabasePath}}" required 42 style="width: 100%; padding: 8px; font-size: 14px;" 43 placeholder="./database.db"> 44 <small style="color: #666;">Path to SQLite database file (requires restart if changed)</small> 45 </div> 46 47 <div style="margin-bottom: 20px;"> 48 <label for="upload_dir" style="display: block; font-weight: bold; margin-bottom: 5px;">Upload Directory:</label> 49 <input type="text" id="upload_dir" name="upload_dir" value="{{.Data.Config.UploadDir}}" required 50 style="width: 100%; padding: 8px; font-size: 14px;" 51 placeholder="uploads"> 52 <small style="color: #666;">Directory where uploaded files are stored</small> 53 </div> 54 55 <div style="margin-bottom: 20px;"> 56 <label for="server_port" style="display: block; font-weight: bold; margin-bottom: 5px;">Server Port:</label> 57 <input type="text" id="server_port" name="server_port" value="{{.Data.Config.ServerPort}}" required 58 style="width: 100%; padding: 8px; font-size: 14px;" 59 placeholder=":8080"> 60 <small style="color: #666;">Port for web server (format: :8080, requires restart if changed)</small> 61 </div> 62 63 <div style="margin-bottom: 20px;"> 64 <label for="instance_name" style="display: block; font-weight: bold; margin-bottom: 5px;">Instance Name:</label> 65 <input type="text" id="instance_name" name="instance_name" value="{{.Data.Config.InstanceName}}" required 66 style="width: 100%; padding: 8px; font-size: 14px;" 67 placeholder="Taggart"> 68 <small style="color: #666;">Instance Name, used in header and title bar</small> 69 </div> 70 71 <div style="margin-bottom: 20px;"> 72 <label for="gallery_size" style="display: block; font-weight: bold; margin-bottom: 5px;">Gallery Size:</label> 73 <input type="text" id="gallery_size" name="gallery_size" value="{{.Data.Config.GallerySize}}" required 74 style="width: 100%; padding: 8px; font-size: 14px;" 75 placeholder="400px"> 76 <small style="color: #666;">Size of previews used in galleries</small> 77 </div> 78 79 <div style="margin-bottom: 20px;"> 80 <label for="items_per_page" style="display: block; font-weight: bold; margin-bottom: 5px;">Items per Page:</label> 81 <input type="text" id="items_per_page" name="items_per_page" value="{{.Data.Config.ItemsPerPage}}" required 82 style="width: 100%; padding: 8px; font-size: 14px;" 83 placeholder="100"> 84 <small style="color: #666;">Items per page in galleries</small> 85 </div> 86 87 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 88 Save Settings 89 </button> 90 </form> 91 92 <div style="margin-top: 40px; padding: 20px; background-color: #f8f9fa; border-radius: 5px;"> 93 <h3>Current Configuration:</h3> 94 <ul> 95 <li><strong>Database:</strong> {{.Data.Config.DatabasePath}}</li> 96 <li><strong>Upload Directory:</strong> {{.Data.Config.UploadDir}}</li> 97 <li><strong>Server Port:</strong> {{.Data.Config.ServerPort}}</li> 98 <li><strong>Instance Name:</strong> {{.Data.Config.InstanceName}}</li> 99 <li><strong>Gallery Size:</strong> {{.Data.Config.GallerySize}}</li> 100 <li><strong>Items per Page:</strong> {{.Data.Config.ItemsPerPage}}</li> 101 </ul> 102 103 <h4>Configuration File:</h4> 104 <p>Settings are stored in <code>config.json</code> in the application directory.</p> 105 </div> 106 </div> 107 108 <!-- Database Tab --> 109 <div id="admin-content-database" style="display: none;"> 110 <h2>Database Maintenance</h2> 111 112 <form method="post" style="margin-bottom: 20px;"> 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="action" value="vacuum"> 122 <button type="submit" style="background-color: #6f42c1; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 123 Vacuum Database 124 </button> 125 <small style="color: #666; margin-left: 10px;">Reclaims unused space and optimizes database performance</small> 126 </form> 127 </div> 128 129 <!-- Aliases Tab --> 130 <div id="admin-content-aliases" style="display: none;"> 131 <h2>Tag Aliases</h2> 132 <p style="color: #666; margin-bottom: 20px;"> 133 Define tag aliases so that multiple tag values are treated as equivalent when searching or filtering. 134 For example, if you alias "colour/blue" with "colour/navy", searching for either will show files tagged with both. 135 </p> 136 137 <div id="aliases-section" style="max-width: 800px;"> 138 <div id="alias-groups"></div> 139 140 <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;"> 141 + Add Alias Group 142 </button> 143 144 <form method="post" id="aliases-form" style="margin-top: 20px;"> 145 <input type="hidden" name="action" value="save_aliases"> 146 <input type="hidden" name="aliases_json" id="aliases_json"> 147 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer;"> 148 Save Aliases 149 </button> 150 </form> 151 </div> 152 </div> 153 154 <!-- Orphans Tab --> 155 <div id="admin-content-orphans" style="display: none;"> 156 <h2>Orphaned Files</h2> 157 <p style="color: #666; margin-bottom: 20px;"> 158 These files exist in the upload directory but are not tracked in the database. 159 </p> 160 161 {{if .Data.Orphans}} 162 <ul style="list-style-type: disc; padding-left: 20px;"> 163 {{range .Data.Orphans}} 164 <li style="margin-bottom: 5px; font-family: monospace;">{{.}}</li> 165 {{end}} 166 </ul> 167 {{else}} 168 <div style="padding: 20px; background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"> 169 <strong>✓ No orphaned files found!</strong> 170 </div> 171 {{end}} 172 </div> 173 174 <!-- Thumbnails Tab --> 175 <div id="admin-content-thumbnails" style="display: none;"> 176 <h2>Thumbnail Management</h2> 177 178 <!-- Sub-tab Navigation --> 179 <div style="margin-bottom: 20px; border-bottom: 1px solid #ddd;"> 180 <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;"> 181 Missing ({{len .Data.MissingThumbnails}}) 182 </button> 183 <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;"> 184 Regenerate 185 </button> 186 </div> 187 188 <!-- Missing Thumbnails Sub-tab --> 189 <div id="thumb-content-missing"> 190 <h3>Missing Thumbnails ({{len .Data.MissingThumbnails}})</h3> 191 192 {{if .Data.MissingThumbnails}} 193 <form method="post" action="/thumbnails/generate" style="margin-bottom: 20px;"> 194 <input type="hidden" name="action" value="generate_all"> 195 <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;"> 196 Generate All Missing Thumbnails 197 </button> 198 <small style="color: #666; margin-left: 10px;">Uses timestamp 00:00:05 for all videos</small> 199 </form> 200 201 <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;"> 202 {{range .Data.MissingThumbnails}} 203 <div style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; background-color: #f8f9fa;"> 204 <h4 style="margin-top: 0; font-size: 14px; word-break: break-word;"> 205 <a href="/file/{{.ID}}" target="_blank">{{.Filename}}</a> 206 </h4> 207 <p style="color: #666; font-size: 12px; margin: 5px 0;">ID: {{.ID}}</p> 208 209 <video width="100%" style="max-height: 200px; background: #000; margin: 10px 0; cursor: pointer;" title="Click to capture frame"> 210 <source src="/uploads/{{.EscapedFilename}}"> 211 </video> 212 213 <form method="post" action="/thumbnails/generate" style="margin-top: 10px;"> 214 <input type="hidden" name="action" value="generate_single"> 215 <input type="hidden" name="file_id" value="{{.ID}}"> 216 <input type="hidden" name="redirect" value="admin"> 217 218 <div style="display: flex; gap: 5px; align-items: center; margin-bottom: 10px;"> 219 <label style="font-size: 13px; white-space: nowrap;">Timestamp:</label> 220 <input type="text" name="timestamp" value="00:00:05" placeholder="00:00:05" 221 style="flex: 1; padding: 5px; font-size: 13px; font-family: monospace;"> 222 </div> 223 224 <button type="submit" style="background-color: #007bff; color: white; padding: 6px 12px; border: none; border-radius: 3px; font-size: 13px; cursor: pointer; width: 100%;"> 225 Generate Thumbnail 226 </button> 227 </form> 228 </div> 229 {{end}} 230 </div> 231 {{else}} 232 <div style="padding: 20px; background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 4px;"> 233 <strong>✓ All videos have thumbnails!</strong> 234 </div> 235 {{end}} 236 </div> 237 238 <!-- Regenerate Sub-tab --> 239 <div id="thumb-content-regenerate" style="display: none;"> 240 <h3>Regenerate Thumbnail</h3> 241 242 <div style="margin-bottom: 20px; padding: 10px; background-color: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 4px;"> 243 <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). 244 </div> 245 246 <form method="post" action="/thumbnails/generate" style="max-width: 500px; padding: 20px; background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 5px;"> 247 <input type="hidden" name="action" value="generate_single"> 248 <input type="hidden" name="redirect" value="admin"> 249 250 <div style="margin-bottom: 20px;"> 251 <label for="file_id" style="display: block; font-weight: bold; margin-bottom: 5px;">File ID:</label> 252 <input type="text" id="file_id" name="file_id" required 253 style="width: 100%; padding: 8px; font-size: 14px; font-family: monospace;" 254 placeholder="e.g., 312"> 255 <small style="color: #666;">Enter the ID of the video file</small> 256 </div> 257 258 <div style="margin-bottom: 20px;"> 259 <label for="timestamp" style="display: block; font-weight: bold; margin-bottom: 5px;">Timestamp:</label> 260 <input type="text" id="timestamp" name="timestamp" value="00:00:05" required 261 style="width: 100%; padding: 8px; font-size: 14px; font-family: monospace;" 262 placeholder="00:00:05"> 263 <small style="color: #666;">Format: HH:MM:SS (e.g., 00:00:05 for 5 seconds)</small> 264 </div> 265 266 <button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; width: 100%;"> 267 Generate/Regenerate Thumbnail 268 </button> 269 </form> 270 </div> 271 </div> 272 273 <script>window.initialAliasGroups = {{.Data.Config.TagAliases}};</script> 274 <script src="/static/tag-alias.js" defer></script> 275 <script src="/static/admin-tabs.js" defer></script> 276 277 {{template "_footer"}}