var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var CONFIG = Object.freeze({
SEARCH_DEBOUNCE_MS: 300,
TOAST_DURATION_MS: 1000,
SCROLL_THRESHOLD: 300,
LAZY_LOAD_MARGIN: "100px",
DEFAULT_ITEMS_PER_PAGE: 20,
});
var DOM = {
gallery: document.getElementById("gallery"),
modal: document.getElementById("modal"),
modal_media: document.getElementById("modalMedia"),
modal_info: document.getElementById("modalInfo"),
modal_counter: document.getElementById("modalCounter"),
search_box: document.getElementById("searchBox"),
search_clear: document.getElementById("searchClear"),
pagination: document.getElementById("pagination"),
stats: document.getElementById("stats"),
bulk_actions: document.getElementById("bulkActions"),
selected_count: document.getElementById("selectedCount"),
scroll_top: document.getElementById("scrollTop"),
adv_filters: document.getElementById("advancedFilters"),
adv_filter_toggle: document.getElementById("advancedFilterToggle"),
toast_container: document.getElementById("toastContainer"),
kb_help: document.getElementById("keyboardHelp"),
items_per_page: document.getElementById("itemsPerPage"),
sort_by: document.getElementById("sortBy"),
sort_order: document.getElementById("sortOrder"),
};
var state = {
filtered_media: [],
current_filter: "all",
current_search: "",
current_modal_idx: -1,
current_view: "grid",
current_sort: "name",
sort_order: "asc",
advanced_filters: {},
selected_items: new Set(),
last_selected_index: -1,
current_page: 1,
items_per_page: CONFIG.DEFAULT_ITEMS_PER_PAGE,
is_loading: false,
image_observer: null,
};
function debounce(fn, delay) {
var timeout_id;
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
clearTimeout(timeout_id);
timeout_id = setTimeout(function () { return fn.apply(void 0, args); }, delay);
};
}
function format_fsize(bytes) {
if (bytes === 0)
return "0 B";
var k = 1024;
var sizes = ["B", "KB", "MB", "GB"];
var i = Math.floor(Math.log(bytes) / Math.log(k));
return "".concat(Math.round((bytes / Math.pow(k, i)) * 100) / 100, " ").concat(sizes[i]);
}
function escape_html(str) {
var div = document.createElement("div");
div.textContent = str;
return div.innerHTML;
}
function show_toast(message, type, duration) {
if (type === void 0) { type = "info"; }
if (duration === void 0) { duration = CONFIG.TOAST_DURATION_MS; }
var toast = document.createElement("div");
toast.className = "toast ".concat(type);
toast.setAttribute("role", "alert");
var icons = {
success: "✓",
error: "✗",
info: "ℹ",
};
toast.innerHTML = "\n <span class=\"toast-icon\" aria-hidden=\"true\">".concat(icons[type], "</span>\n <div class=\"toast-content\">").concat(escape_html(message), "</div>\n <button class=\"toast-close\" aria-label=\"Dismiss notification\">\u00D7</button>\n ");
var close_btn = toast.querySelector(".toast-close");
close_btn === null || close_btn === void 0 ? void 0 : close_btn.addEventListener("click", function () { return remove_toast(toast); });
DOM.toast_container.appendChild(toast);
var timeoutId = setTimeout(function () { return remove_toast(toast); }, duration);
toast.dataset.timeoutId = String(timeoutId);
}
function remove_toast(toast) {
if (!toast.parentNode)
return;
clearTimeout(Number(toast.dataset.timeoutId));
toast.style.animation = "slideInRight 0.3s ease reverse";
toast.addEventListener("animationend", function () { return toast.remove(); }, { once: true });
}
function setup_lazy_loading() {
if (state.image_observer) {
state.image_observer.disconnect();
}
state.image_observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
var _a;
if (entry.isIntersecting) {
var img_1 = entry.target;
if (img_1.dataset.src) {
img_1.src = img_1.dataset.src;
img_1.removeAttribute("data-src");
img_1.classList.remove("loading");
img_1.addEventListener("load", function () { return img_1.classList.add("loaded"); }, {
once: true,
});
img_1.addEventListener("error", function () {
img_1.classList.remove("loading");
img_1.alt = "Failed to load image";
}, { once: true });
}
(_a = state.image_observer) === null || _a === void 0 ? void 0 : _a.unobserve(img_1);
}
});
}, { rootMargin: CONFIG.LAZY_LOAD_MARGIN });
document
.querySelectorAll("img[data-src]")
.forEach(function (img) {
var _a;
(_a = state.image_observer) === null || _a === void 0 ? void 0 : _a.observe(img);
});
}
function load_media() {
return __awaiter(this, void 0, void 0, function () {
var params, filterMappings, _i, _a, _b, key, param, filterKey, response, _c, error_1, error_msg;
var _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (state.is_loading)
return [2 /*return*/];
state.is_loading = true;
_e.label = 1;
case 1:
_e.trys.push([1, 4, 5, 6]);
params = new URLSearchParams();
if (state.current_search)
params.append("search", state.current_search);
if (state.current_filter !== "all") {
params.append("media_type", state.current_filter);
}
filterMappings = {
rating: "rating",
artist: "artist",
tag: "tag",
extension: "extension",
min_score: "min_score",
max_score: "max_score",
min_fav: "min_fav",
post_id: "post_id",
pool_id: "pool_id",
min_width: "min_width",
min_height: "min_height",
aspect_ratio: "aspect_ratio",
};
for (_i = 0, _a = Object.entries(filterMappings); _i < _a.length; _i++) {
_b = _a[_i], key = _b[0], param = _b[1];
filterKey = key;
if (state.advanced_filters[filterKey]) {
params.append(param, state.advanced_filters[filterKey]);
}
}
return [4 /*yield*/, fetch("/api/media?".concat(params))];
case 2:
response = _e.sent();
if (!response.ok) {
throw new Error("Server error: ".concat(response.status));
}
_c = state;
return [4 /*yield*/, response.json()];
case 3:
_c.filtered_media = (_e.sent());
apply_sorting();
render_gallery();
update_stats();
render_pagination_controls();
return [3 /*break*/, 6];
case 4:
error_1 = _e.sent();
console.error("Error loading media:", error_1);
error_msg = error_1 instanceof Error ? error_1.message : "Unknown error";
DOM.gallery.innerHTML = "\n <div class=\"empty\">\n <h2>Error loading downloads</h2>\n <p>".concat(escape_html(error_msg), "</p>\n <button class=\"btn\" id=\"retryLoad\">Retry</button>\n </div>\n ");
(_d = document.getElementById("retryLoad")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", load_media);
show_toast("Failed to load media", "error");
return [3 /*break*/, 6];
case 5:
state.is_loading = false;
return [7 /*endfinally*/];
case 6: return [2 /*return*/];
}
});
});
}
function apply_sorting() {
var _a;
if (state.current_sort === "random") {
for (var i = state.filtered_media.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
_a = [
state.filtered_media[j],
state.filtered_media[i],
], state.filtered_media[i] = _a[0], state.filtered_media[j] = _a[1];
}
return;
}
var sort_funcs = {
name: function (a, b) { return a.name.localeCompare(b.name); },
size: function (a, b) { return a.size - b.size; },
date: function (a, b) {
var _a, _b;
return (((_a = a.metadata) === null || _a === void 0 ? void 0 : _a.created_at) || "").localeCompare(((_b = b.metadata) === null || _b === void 0 ? void 0 : _b.created_at) || "");
},
score: function (a, b) { var _a, _b; return (((_a = a.metadata) === null || _a === void 0 ? void 0 : _a.score) || 0) - (((_b = b.metadata) === null || _b === void 0 ? void 0 : _b.score) || 0); },
fav_count: function (a, b) { var _a, _b; return (((_a = a.metadata) === null || _a === void 0 ? void 0 : _a.fav_count) || 0) - (((_b = b.metadata) === null || _b === void 0 ? void 0 : _b.fav_count) || 0); },
};
var sort_func = sort_funcs[state.current_sort];
if (sort_func) {
state.filtered_media.sort(function (a, b) {
var result = sort_func(a, b);
return state.sort_order === "asc" ? result : -result;
});
}
}
function render_gallery() {
DOM.gallery.className = "gallery ".concat(state.current_view, "-view");
if (state.filtered_media.length === 0) {
DOM.gallery.innerHTML = "\n <div class=\"empty\">\n <h2>No downloads found</h2>\n <p>Try adjusting your filters or search query.</p>\n </div>\n ";
return;
}
var start_idx = (state.current_page - 1) * state.items_per_page;
var end_idx = Math.min(start_idx + state.items_per_page, state.filtered_media.length);
var page_media = state.filtered_media.slice(start_idx, end_idx);
var fragment = document.createDocumentFragment();
page_media.forEach(function (item, index) {
var global_idx = start_idx + index;
var is_selected = state.selected_items.has(global_idx);
var card = create_media_card(item, global_idx, is_selected);
fragment.appendChild(card);
});
DOM.gallery.innerHTML = "";
DOM.gallery.appendChild(fragment);
setup_lazy_loading();
setup_video_hover();
}
function create_media_card(item, global_idx, is_selected) {
var card = document.createElement("div");
card.className = "media-card".concat(is_selected ? " selected" : "");
card.dataset.index = String(global_idx);
card.setAttribute("role", "gridcell");
card.setAttribute("tabindex", "0");
var meta = item.metadata;
var ratingClass = meta ? "rating-".concat(meta.rating) : "";
card.innerHTML = "\n <div class=\"media-preview-container\">\n ".concat(item.media_type === "video"
? "<video class=\"media-preview\" src=\"".concat(escape_html(item.path), "\" preload=\"metadata\" loop muted></video>")
: "<img class=\"media-preview loading\" data-src=\"".concat(escape_html(item.path), "\" alt=\"").concat(escape_html(item.name), "\">"), "\n <div class=\"media-overlay\">\n <div class=\"quick-actions\">\n <button class=\"quick-action select-btn\" title=\"Select\" aria-label=\"Select item\">\u2611</button>\n <button class=\"quick-action download-btn\" title=\"Download\" aria-label=\"Download item\">\u2B07</button>\n </div>\n <span class=\"media-type ").concat(item.media_type, "\">").concat(item.media_type, "</span>\n </div>\n </div>\n <div class=\"media-info\">\n <div class=\"media-name\">").concat(escape_html(item.name), "</div>\n <div class=\"media-meta\">\n <span>").concat(format_fsize(item.size), "</span>\n </div>\n ").concat(meta
? "\n <div class=\"media-metadata\">\n <div class=\"metadata-row\">\n <span class=\"metadata-label\">ID:</span>\n <span class=\"metadata-value\">".concat(meta.id, "</span>\n </div>\n <div class=\"metadata-row\">\n <span class=\"metadata-label\">Artist:</span>\n <span class=\"metadata-value\">").concat(escape_html(meta.artists.join(", ") || "Unknown"), "</span>\n </div>\n <div class=\"metadata-row\">\n <span class=\"metadata-label\">Rating:</span>\n <span class=\"rating-badge ").concat(ratingClass, "\">").concat(meta.rating.toUpperCase(), "</span>\n </div>\n <div class=\"metadata-row\">\n <span class=\"metadata-label\">Score:</span>\n <span class=\"metadata-value\">").concat(meta.score, "</span>\n </div>\n ").concat(meta.artists.length > 0
? "\n <div class=\"tag-list\">\n ".concat(meta.artists
.slice(0, 3)
.map(function (a) {
return "<button class=\"tag artist\" data-artist=\"".concat(escape_html(a), "\">").concat(escape_html(a), "</button>");
})
.join(""), "\n </div>\n ")
: "", "\n </div>\n ")
: "", "\n </div>\n ");
card.addEventListener("click", function (e) {
var target = e.target;
if (target.closest(".select-btn")) {
e.stopPropagation();
toggle_select_with_shift(global_idx, e);
return;
}
if (target.closest(".download-btn")) {
e.stopPropagation();
download_media(global_idx);
return;
}
if (target.closest(".tag.artist")) {
e.stopPropagation();
var artist = target.dataset.artist;
if (artist)
filter_by_tag(artist, "artist");
return;
}
open_modal(global_idx);
});
card.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
open_modal(global_idx);
}
});
return card;
}
function setup_video_hover() {
if (state.current_view === "grid" || state.current_view === "compact") {
document
.querySelectorAll(".media-card video")
.forEach(function (video) {
var card = video.closest(".media-card");
card === null || card === void 0 ? void 0 : card.addEventListener("mouseenter", function () {
video.play().catch(function () { });
});
card === null || card === void 0 ? void 0 : card.addEventListener("mouseleave", function () {
video.pause();
video.currentTime = 0;
});
});
}
}
function toggle_select_with_shift(index, event) {
var _a;
if ((event === null || event === void 0 ? void 0 : event.shiftKey) && state.last_selected_index !== -1) {
var start = Math.min(state.last_selected_index, index);
var end = Math.max(state.last_selected_index, index);
for (var i = start; i <= end; i++) {
state.selected_items.add(i);
(_a = document.querySelector("[data-index=\"".concat(i, "\"]"))) === null || _a === void 0 ? void 0 : _a.classList.add("selected");
}
show_toast("Selected ".concat(end - start + 1, " items"), "success", 2000);
}
else {
toggle_select(index);
}
state.last_selected_index = index;
}
function toggle_select(index) {
var _a;
if (state.selected_items.has(index)) {
state.selected_items.delete(index);
}
else {
state.selected_items.add(index);
}
(_a = document
.querySelector("[data-index=\"".concat(index, "\"]"))) === null || _a === void 0 ? void 0 : _a.classList.toggle("selected");
update_bulk_actions();
}
function select_all_visible() {
var _a;
var start_idx = (state.current_page - 1) * state.items_per_page;
var end_idx = Math.min(start_idx + state.items_per_page, state.filtered_media.length);
for (var i = start_idx; i < end_idx; i++) {
state.selected_items.add(i);
(_a = document.querySelector("[data-index=\"".concat(i, "\"]"))) === null || _a === void 0 ? void 0 : _a.classList.add("selected");
}
update_bulk_actions();
show_toast("Selected ".concat(end_idx - start_idx, " items"), "success", 2000);
}
function clear_sel() {
var count = state.selected_items.size;
state.selected_items.clear();
state.last_selected_index = -1;
document.querySelectorAll(".media-card.selected").forEach(function (card) {
card.classList.remove("selected");
});
update_bulk_actions();
update_stats();
if (count > 0) {
show_toast("Cleared ".concat(count, " selections"), "info", 2000);
}
}
function update_bulk_actions() {
DOM.selected_count.textContent = "".concat(state.selected_items.size, " selected");
DOM.bulk_actions.hidden = state.selected_items.size === 0;
}
function download_media(index) {
var item = state.filtered_media[index];
if (!item)
return;
var link = document.createElement("a");
link.href = item.path;
link.download = item.name;
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
show_toast("Downloading ".concat(item.name), "success", 2000);
}
function download_selected() {
var count = 0;
state.selected_items.forEach(function (index) {
download_media(index);
count++;
});
show_toast("Downloading ".concat(count, " items"), "success", 3000);
}
function filter_by_tag(tag, type) {
var input = document.getElementById(type === "artist" ? "artistFilter" : "tagFilter");
if (input) {
input.value = tag;
}
DOM.adv_filters.hidden = false;
DOM.adv_filter_toggle.setAttribute("aria-expanded", "true");
apply_adv_filters();
show_toast("Filtering by ".concat(type, ": ").concat(tag), "info", 2000);
}
function apply_adv_filters() {
var get_input_val = function (id) {
var el = document.getElementById(id);
return (el === null || el === void 0 ? void 0 : el.value) || "";
};
state.advanced_filters = {
rating: get_input_val("ratingFilter"),
artist: get_input_val("artistFilter"),
tag: get_input_val("tagFilter"),
extension: get_input_val("extensionFilter"),
min_score: get_input_val("minScoreFilter"),
max_score: get_input_val("maxScoreFilter"),
min_fav: get_input_val("minFavFilter"),
post_id: get_input_val("postIdFilter"),
pool_id: get_input_val("poolIdFilter"),
min_width: get_input_val("minWidthFilter"),
min_height: get_input_val("minHeightFilter"),
aspect_ratio: get_input_val("aspectRatioFilter"),
};
state.current_page = 1;
load_media();
show_toast("Filters applied", "success", 2000);
}
function clear_all_filters() {
state.current_search = "";
state.current_filter = "all";
state.advanced_filters = {};
state.current_page = 1;
clear_sel();
DOM.search_box.value = "";
DOM.search_clear.hidden = true;
var filter_ids = [
"ratingFilter",
"artistFilter",
"tagFilter",
"extensionFilter",
"minScoreFilter",
"maxScoreFilter",
"minFavFilter",
"postIdFilter",
"poolIdFilter",
"minWidthFilter",
"minHeightFilter",
"aspectRatioFilter",
];
filter_ids.forEach(function (id) {
var el = document.getElementById(id);
if (el)
el.value = "";
});
document
.querySelectorAll(".filter-btn[data-filter]")
.forEach(function (b) {
b.classList.toggle("active", b.dataset.filter === "all");
b.setAttribute("aria-pressed", String(b.dataset.filter === "all"));
});
load_media();
show_toast("All filters cleared", "success", 2000);
}
function update_stats() {
var stats_info = DOM.stats.querySelector(".stats-info");
if (!stats_info)
return;
var images = state.filtered_media.filter(function (m) { return m.media_type === "image"; }).length;
var videos = state.filtered_media.filter(function (m) { return m.media_type === "video"; }).length;
var total_size = state.filtered_media.reduce(function (sum, item) { return sum + item.size; }, 0);
var filter_info = [];
if (state.current_search)
filter_info.push("search: \"".concat(state.current_search, "\""));
if (state.advanced_filters.rating)
filter_info.push("rating: ".concat(state.advanced_filters.rating));
if (state.advanced_filters.artist)
filter_info.push("artist: ".concat(state.advanced_filters.artist));
if (state.advanced_filters.tag)
filter_info.push("tag: ".concat(state.advanced_filters.tag));
var filter_text = filter_info.length > 0 ? " (".concat(filter_info.join(", "), ")") : "";
stats_info.innerHTML = "\n <div class=\"stat-item\"><strong>".concat(state.filtered_media.length, "</strong> items</div>\n <div class=\"stat-item\"><strong>").concat(images, "</strong> images</div>\n <div class=\"stat-item\"><strong>").concat(videos, "</strong> videos</div>\n <div class=\"stat-item\"><strong>").concat(format_fsize(total_size), "</strong> total</div>\n ").concat(filter_text ? "<div class=\"stat-item\" style=\"color: var(--iris);\">".concat(escape_html(filter_text), "</div>") : "", "\n ").concat(state.selected_items.size > 0 ? "<div class=\"stat-item selection-count\">".concat(state.selected_items.size, " selected</div>") : "", "\n ");
}
function render_pagination_controls() {
var total_items = state.filtered_media.length;
var total_pages = Math.ceil(total_items / state.items_per_page);
if (total_pages <= 1) {
DOM.pagination.innerHTML = "";
return;
}
var show_pages = 5;
var start_page = Math.max(1, state.current_page - Math.floor(show_pages / 2));
var end_page = Math.min(total_pages, start_page + show_pages - 1);
if (end_page - start_page < show_pages - 1) {
start_page = Math.max(1, end_page - show_pages + 1);
}
var html = "\n <button class=\"btn page-button\" data-action=\"prev\" ".concat(state.current_page === 1 ? "disabled" : "", ">\u00AB Prev</button>\n ");
if (start_page > 1) {
html += "<button class=\"btn page-button\" data-page=\"1\">1</button>";
if (start_page > 2)
html += "<span class=\"page-ellipsis\">...</span>";
}
for (var i = start_page; i <= end_page; i++) {
html += "<button class=\"btn page-button".concat(i === state.current_page ? " active" : "", "\" data-page=\"").concat(i, "\" ").concat(i === state.current_page ? 'aria-current="page"' : "", ">").concat(i, "</button>");
}
if (end_page < total_pages) {
if (end_page < total_pages - 1)
html += "<span class=\"page-ellipsis\">...</span>";
html += "<button class=\"btn page-button\" data-page=\"".concat(total_pages, "\">").concat(total_pages, "</button>");
}
html += "\n <button class=\"btn page-button\" data-action=\"next\" ".concat(state.current_page === total_pages ? "disabled" : "", ">Next \u00BB</button>\n <div class=\"page-jump\">\n <label for=\"pageJumpInput\" class=\"visually-hidden\">Jump to page</label>\n <input type=\"number\" id=\"pageJumpInput\" class=\"input-base\" min=\"1\" max=\"").concat(total_pages, "\" value=\"").concat(state.current_page, "\" inputmode=\"numeric\">\n <button class=\"btn page-button\" data-action=\"jump\">Go</button>\n </div>\n ");
DOM.pagination.innerHTML = html;
}
function goto_page(page) {
var totalPages = Math.ceil(state.filtered_media.length / state.items_per_page);
if (page >= 1 && page <= totalPages && page !== state.current_page) {
state.current_page = page;
render_gallery();
render_pagination_controls();
window.scrollTo({ top: 0, behavior: "smooth" });
}
}
function open_modal(index) {
state.current_modal_idx = index;
show_modal_media();
DOM.modal.showModal();
document.body.style.overflow = "hidden";
}
function close_modal() {
var _a;
DOM.modal.close();
DOM.modal_info.hidden = true;
(_a = document
.getElementById("modalMetadata")) === null || _a === void 0 ? void 0 : _a.setAttribute("aria-pressed", "false");
document.body.style.overflow = "";
}
function show_modal_media() {
var item = state.filtered_media[state.current_modal_idx];
if (!item)
return;
DOM.modal_counter.textContent = "".concat(state.current_modal_idx + 1, " / ").concat(state.filtered_media.length);
var isVideo = item.media_type === "video";
var newMedia;
if (isVideo) {
newMedia = document.createElement("video");
newMedia.src = item.path;
newMedia.controls = true;
newMedia.autoplay = true;
newMedia.loop = true;
}
else {
newMedia = document.createElement("img");
newMedia.src = item.path;
newMedia.alt = item.name;
}
newMedia.className = "modal-media";
newMedia.id = "modalMedia";
DOM.modal_media.replaceWith(newMedia);
DOM.modal_media = newMedia;
var meta = item.metadata;
if (meta) {
DOM.modal_info.innerHTML = "\n <h3>".concat(escape_html(item.name), "</h3>\n <p><strong>ID:</strong> ").concat(meta.id, " | <strong>Rating:</strong> ").concat(meta.rating.toUpperCase(), " | <strong>Score:</strong> ").concat(meta.score, " | <strong>Favorites:</strong> ").concat(meta.fav_count, "</p>\n ").concat(meta.artists.length > 0 ? "<p><strong>Artists:</strong> ".concat(escape_html(meta.artists.join(", ")), "</p>") : "", "\n ").concat(meta.tags.length > 0 ? "<p><strong>Tags:</strong> ".concat(escape_html(meta.tags.slice(0, 20).join(", "))).concat(meta.tags.length > 20 ? "..." : "", "</p>") : "", "\n ").concat(meta.character_tags.length > 0 ? "<p><strong>Characters:</strong> ".concat(escape_html(meta.character_tags.join(", ")), "</p>") : "", "\n ").concat(meta.species_tags.length > 0 ? "<p><strong>Species:</strong> ".concat(escape_html(meta.species_tags.join(", ")), "</p>") : "", "\n <p><strong>Created:</strong> ").concat(new Date(meta.created_at).toLocaleString(), "</p>\n <p><strong>Size:</strong> ").concat(format_fsize(item.size), "</p>\n ");
}
else {
DOM.modal_info.innerHTML = "\n <h3>".concat(escape_html(item.name), "</h3>\n <p><strong>Size:</strong> ").concat(format_fsize(item.size), "</p>\n <p>No metadata available</p>\n ");
}
}
function nav_modal(direction) {
var length = state.filtered_media.length;
state.current_modal_idx =
(state.current_modal_idx + direction + length) % length;
show_modal_media();
}
function toggle_modal_info() {
var _a;
var isHidden = DOM.modal_info.hidden;
DOM.modal_info.hidden = !isHidden;
(_a = document
.getElementById("modalMetadata")) === null || _a === void 0 ? void 0 : _a.setAttribute("aria-pressed", String(isHidden));
}
function toggle_fullscreen() {
return __awaiter(this, void 0, void 0, function () {
var modalContent, err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
modalContent = document.querySelector(".modal-content");
if (!modalContent)
return [2 /*return*/];
_a.label = 1;
case 1:
_a.trys.push([1, 6, , 7]);
if (!!document.fullscreenElement) return [3 /*break*/, 3];
return [4 /*yield*/, modalContent.requestFullscreen()];
case 2:
_a.sent();
return [3 /*break*/, 5];
case 3: return [4 /*yield*/, document.exitFullscreen()];
case 4:
_a.sent();
_a.label = 5;
case 5: return [3 /*break*/, 7];
case 6:
err_1 = _a.sent();
console.error("Fullscreen error:", err_1);
show_toast("Fullscreen not supported", "error", 2000);
return [3 /*break*/, 7];
case 7: return [2 /*return*/];
}
});
});
}
function open_kbhelp() {
DOM.kb_help.showModal();
}
function close_kbhelp() {
DOM.kb_help.close();
}
function setup_evlisteners() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
var debouncedSearch = debounce(function () {
state.current_search = DOM.search_box.value;
state.current_page = 1;
load_media();
}, CONFIG.SEARCH_DEBOUNCE_MS);
DOM.search_box.addEventListener("input", function (e) {
var target = e.target;
DOM.search_clear.hidden = target.value.length === 0;
debouncedSearch();
});
DOM.search_clear.addEventListener("click", function () {
DOM.search_box.value = "";
DOM.search_clear.hidden = true;
state.current_search = "";
state.current_page = 1;
load_media();
});
document
.querySelectorAll(".filter-btn[data-filter]")
.forEach(function (btn) {
btn.addEventListener("click", function () {
document
.querySelectorAll(".filter-btn[data-filter]")
.forEach(function (b) {
b.classList.remove("active");
b.setAttribute("aria-pressed", "false");
});
btn.classList.add("active");
btn.setAttribute("aria-pressed", "true");
state.current_filter = btn.dataset.filter;
state.current_page = 1;
load_media();
});
});
document.querySelectorAll(".view-btn").forEach(function (btn) {
btn.addEventListener("click", function () {
document.querySelectorAll(".view-btn").forEach(function (b) {
b.classList.remove("active");
b.setAttribute("aria-pressed", "false");
});
btn.classList.add("active");
btn.setAttribute("aria-pressed", "true");
state.current_view = btn.dataset.view;
render_gallery();
show_toast("View changed to ".concat(state.current_view), "info", 1500);
});
});
DOM.sort_by.addEventListener("change", function (e) {
var target = e.target;
state.current_sort = target.value;
apply_sorting();
render_gallery();
render_pagination_controls();
});
DOM.sort_order.addEventListener("click", function () {
state.sort_order = state.sort_order === "asc" ? "desc" : "asc";
DOM.sort_order.textContent = state.sort_order === "asc" ? "↑" : "↓";
DOM.sort_order.setAttribute("aria-label", "Sort ".concat(state.sort_order === "asc" ? "ascending" : "descending", ", click to toggle"));
DOM.sort_order.dataset.order = state.sort_order;
apply_sorting();
render_gallery();
render_pagination_controls();
});
DOM.items_per_page.addEventListener("change", function (e) {
var target = e.target;
state.items_per_page = parseInt(target.value, 10);
state.current_page = 1;
render_gallery();
render_pagination_controls();
show_toast("Showing ".concat(state.items_per_page, " items per page"), "info", 2000);
});
DOM.adv_filter_toggle.addEventListener("click", function () {
var isHidden = DOM.adv_filters.hidden;
DOM.adv_filters.hidden = !isHidden;
DOM.adv_filter_toggle.setAttribute("aria-expanded", String(isHidden));
});
(_a = document
.getElementById("applyFilters")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", apply_adv_filters);
(_b = document
.getElementById("clearFilters")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", clear_all_filters);
(_c = document
.getElementById("downloadSelected")) === null || _c === void 0 ? void 0 : _c.addEventListener("click", download_selected);
(_d = document
.getElementById("clearSelection")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", clear_sel);
DOM.pagination.addEventListener("click", function (e) {
var btn = e.target.closest("button");
if (!btn)
return;
var page = btn.dataset.page;
var action = btn.dataset.action;
if (page) {
goto_page(parseInt(page, 10));
}
else if (action === "prev") {
goto_page(state.current_page - 1);
}
else if (action === "next") {
goto_page(state.current_page + 1);
}
else if (action === "jump") {
var input = document.getElementById("pageJumpInput");
if (input)
goto_page(parseInt(input.value, 10));
}
});
DOM.pagination.addEventListener("keydown", function (e) {
var target = e.target;
if (e.key === "Enter" && target.id === "pageJumpInput") {
goto_page(parseInt(target.value, 10));
}
});
window.addEventListener("scroll", function () {
DOM.scroll_top.hidden = window.pageYOffset <= CONFIG.SCROLL_THRESHOLD;
}, { passive: true });
DOM.scroll_top.addEventListener("click", function () {
window.scrollTo({ top: 0, behavior: "smooth" });
});
(_e = document.getElementById("modalClose")) === null || _e === void 0 ? void 0 : _e.addEventListener("click", close_modal);
(_f = document
.getElementById("modalNext")) === null || _f === void 0 ? void 0 : _f.addEventListener("click", function () { return nav_modal(1); });
(_g = document
.getElementById("modalPrev")) === null || _g === void 0 ? void 0 : _g.addEventListener("click", function () { return nav_modal(-1); });
(_h = document
.getElementById("modalDownload")) === null || _h === void 0 ? void 0 : _h.addEventListener("click", function () { return download_media(state.current_modal_idx); });
(_j = document
.getElementById("modalFullscreen")) === null || _j === void 0 ? void 0 : _j.addEventListener("click", toggle_fullscreen);
(_k = document
.getElementById("modalMetadata")) === null || _k === void 0 ? void 0 : _k.addEventListener("click", toggle_modal_info);
DOM.modal.addEventListener("click", function (e) {
if (e.target === DOM.modal)
close_modal();
});
DOM.modal.addEventListener("cancel", function (e) {
e.preventDefault();
close_modal();
});
(_l = document
.getElementById("keyboardHintBtn")) === null || _l === void 0 ? void 0 : _l.addEventListener("click", open_kbhelp);
(_m = document
.getElementById("closeKeyboardHelp")) === null || _m === void 0 ? void 0 : _m.addEventListener("click", close_kbhelp);
DOM.kb_help.addEventListener("click", function (e) {
if (e.target === DOM.kb_help)
close_kbhelp();
});
document.addEventListener("fullscreenchange", function () {
var btn = document.getElementById("modalFullscreen");
if (btn) {
btn.title = document.fullscreenElement
? "Exit Fullscreen"
: "Toggle fullscreen";
}
});
document.addEventListener("keydown", handle_key_down);
}
function handle_key_down(e) {
if (DOM.modal.open) {
switch (e.key) {
case "Escape":
close_modal();
return;
case "ArrowRight":
case "d":
case "D":
nav_modal(1);
return;
case "ArrowLeft":
case "A":
case "a":
nav_modal(-1);
return;
case "d":
case "D":
download_media(state.current_modal_idx);
return;
case "i":
case "I":
toggle_modal_info();
return;
case "f":
case "F":
toggle_fullscreen();
return;
}
return;
}
if (DOM.kb_help.open) {
if (e.key === "Escape")
close_kbhelp();
return;
}
var target = e.target;
if (target.tagName === "INPUT" || target.tagName === "SELECT") {
return;
}
switch (e.key) {
case "n":
case "N":
goto_page(state.current_page + 1);
break;
case "p":
case "P":
goto_page(state.current_page - 1);
break;
case "?":
open_kbhelp();
break;
case "/":
e.preventDefault();
DOM.search_box.focus();
break;
case "Escape":
if (state.selected_items.size > 0) {
clear_sel();
}
break;
case "a":
case "A":
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
select_all_visible();
}
break;
}
}
function init() {
state.items_per_page = parseInt(DOM.items_per_page.value, 10);
setup_evlisteners();
load_media();
show_toast("Press ? for keyboard shortcuts", "info", 4000);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
}
else {
init();
}