diff --git a/admin.php b/admin.php
new file mode 100644
index 0000000..0115dd4
--- /dev/null
+++ b/admin.php
@@ -0,0 +1,101 @@
+
+
+
+
+
+ Admin - Album Passwords
+
+
+
+
+
Administrator Mode
+
+ "; ?>
+
+
+
+ $success"; ?>
+
+ Current Album Passwords:
+
+ $pw): ?>
+ - = htmlspecialchars($album) ?>: = htmlspecialchars($pw) ?>
+
+
+
+
+
+
diff --git a/index.html b/index.html
index f54b225..2cbf316 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
- Christiana Varner - Portland State University - Graduation 2025
+ Album Viewer
- Christiana Varner - Portland State University - Graduation 2025
+
+ Album Viewer
+
Download All
@@ -33,60 +35,130 @@
const gallery = document.getElementById('gallery');
const selectBtn = document.getElementById('select-images');
let downloadBtn = null;
+ let albums = {};
+
+ function getQueryParam(name) {
+ const urlParams = new URLSearchParams(window.location.search);
+ return urlParams.get(name);
+ }
+
+ function renderGallery(images) {
+ gallery.innerHTML = '';
+ images.forEach((imgObj, idx) => {
+ const itemDiv = document.createElement('div');
+ itemDiv.style.position = 'relative';
+
+ const checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.className = 'img-checkbox';
+ checkbox.style.position = 'absolute';
+ checkbox.style.top = '8px';
+ checkbox.style.left = '8px';
+ checkbox.value = imgObj.full;
+ checkbox.style.display = 'none';
+
+ const link = document.createElement('a');
+ link.href = imgObj.full;
+ link.target = '_blank';
+ const img = document.createElement('img');
+ img.src = imgObj.thumb;
+ img.alt = imgObj.full;
+ link.appendChild(img);
+
+ itemDiv.addEventListener('click', function(e) {
+ if (checkbox.style.display === 'block') {
+ if (e.target === img || e.target === itemDiv) {
+ checkbox.checked = !checkbox.checked;
+ e.preventDefault();
+ }
+ }
+ });
+
+ itemDiv.appendChild(checkbox);
+ itemDiv.appendChild(link);
+ gallery.appendChild(itemDiv);
+ });
+ }
fetch('list-images.php')
.then(response => response.json())
- .then(images => {
- images.forEach((imgObj, idx) => {
- // Container for image and checkbox
- const itemDiv = document.createElement('div');
- itemDiv.style.position = 'relative';
-
- // Checkbox (hidden by default)
- const checkbox = document.createElement('input');
- checkbox.type = 'checkbox';
- checkbox.className = 'img-checkbox';
- checkbox.style.position = 'absolute';
- checkbox.style.top = '8px';
- checkbox.style.left = '8px';
- checkbox.value = imgObj.full;
- checkbox.style.display = 'none';
-
- // Image link
- const link = document.createElement('a');
- link.href = imgObj.full;
- link.target = '_blank';
- const img = document.createElement('img');
- img.src = imgObj.thumb;
- img.alt = imgObj.full;
- link.appendChild(img);
-
- // Make image clickable for selection in select mode
- itemDiv.addEventListener('click', function(e) {
- // Only toggle if in select mode (checkboxes visible)
- if (checkbox.style.display === 'block') {
- // Prevent link from opening when selecting
- if (e.target === img || e.target === itemDiv) {
- checkbox.checked = !checkbox.checked;
- e.preventDefault();
- }
- }
+ .then(data => {
+ albums = data;
+ const albumName = getQueryParam('album');
+ if (!albumName) {
+ // Landing page: show album links
+ gallery.innerHTML = 'Welcome!
Select an album to view photos:
';
+ const albumList = document.createElement('div');
+ albumList.style.display = 'flex';
+ albumList.style.flexWrap = 'wrap';
+ albumList.style.justifyContent = 'center';
+ albumList.style.gap = '20px';
+ Object.keys(albums).forEach(album => {
+ const link = document.createElement('a');
+ link.href = `index.html?album=${encodeURIComponent(album)}`;
+ link.textContent = album + (albums[album].protected ? ' 🔒' : '');
+ link.style.display = 'inline-block';
+ link.style.padding = '16px 32px';
+ link.style.background = '#0078d4';
+ link.style.color = '#fff';
+ link.style.borderRadius = '8px';
+ link.style.fontWeight = 'bold';
+ link.style.fontSize = '20px';
+ link.style.textDecoration = 'none';
+ link.style.boxShadow = '0 2px 8px rgba(0,0,0,0.12)';
+ albumList.appendChild(link);
+ });
+ gallery.appendChild(albumList);
+ selectBtn.style.display = 'none';
+ return;
+ }
+ if (!albums[albumName]) {
+ gallery.innerHTML = 'Album not found. Please specify a valid album in the URL (e.g., ?album=Album1).
';
+ selectBtn.style.display = 'none';
+ return;
+ }
+ // Check if album is protected
+ if (albums[albumName].protected) {
+ let password = localStorage.getItem('album_pw_' + albumName) || '';
+ function requestImages(pw) {
+ fetch(`list-images.php?album=${encodeURIComponent(albumName)}&password=${encodeURIComponent(pw)}`)
+ .then(resp => {
+ if (resp.status === 403) {
+ throw new Error('Password required');
+ }
+ return resp.json();
+ })
+ .then(images => {
+ renderGallery(images);
+ selectBtn.style.display = 'inline-block';
+ localStorage.setItem('album_pw_' + albumName, pw);
+ })
+ .catch(() => {
+ gallery.innerHTML = ``;
+ selectBtn.style.display = 'none';
+ document.getElementById('pwform').onsubmit = function(e) {
+ e.preventDefault();
+ const pwTry = document.getElementById('album_pw').value;
+ requestImages(pwTry);
+ };
+ });
+ }
+ requestImages(password);
+ return;
+ }
+ // Not protected, fetch images
+ fetch(`list-images.php?album=${encodeURIComponent(albumName)}`)
+ .then(resp => resp.json())
+ .then(images => {
+ renderGallery(images);
+ selectBtn.style.display = 'inline-block';
});
- itemDiv.appendChild(checkbox);
- itemDiv.appendChild(link);
- gallery.appendChild(itemDiv);
- });
-
- // Add select button logic
selectBtn.addEventListener('click', () => {
- // Show checkboxes
document.querySelectorAll('.img-checkbox').forEach(cb => {
cb.style.display = 'block';
});
- // Hide select button
selectBtn.style.display = 'none';
- // Create and show download selected button
downloadBtn = document.createElement('button');
downloadBtn.id = 'download-selected';
downloadBtn.textContent = 'Download Selected';
diff --git a/list-images.php b/list-images.php
index 214b1f1..df264b2 100644
--- a/list-images.php
+++ b/list-images.php
@@ -1,24 +1,57 @@
'Album not found']);
+ exit;
+ }
+ if (isset($passwords[$album]) && $passwords[$album] !== '') {
+ if ($pw !== $passwords[$album]) {
+ http_response_code(403);
+ echo json_encode(['error' => 'Password required']);
+ exit;
+ }
+ }
+ $albumImages = [];
+ $thumbDir = $dir . $album . '/thumbnails/';
+ $albumDir = $dir . $album . '/';
+ foreach (scandir($albumDir) as $file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (in_array($ext, $extensions)) {
- $thumbPath = 'images/thumbnails/' . $file;
- $fullPath = 'images/' . $file;
- // Check if thumbnail exists
+ $thumbPath = 'images/' . $album . '/thumbnails/' . $file;
+ $fullPath = 'images/' . $album . '/' . $file;
if (file_exists($thumbDir . $file)) {
- $images[] = ['thumb' => $thumbPath, 'full' => $fullPath];
+ $albumImages[] = ['thumb' => $thumbPath, 'full' => $fullPath];
} else {
- $images[] = ['thumb' => $fullPath, 'full' => $fullPath];
+ $albumImages[] = ['thumb' => $fullPath, 'full' => $fullPath];
}
}
}
+ header('Content-Type: application/json');
+ echo json_encode($albumImages);
+ exit;
+}
+
+// Otherwise, return album list (for landing page)
+if (is_dir($dir)) {
+ foreach (scandir($dir) as $album) {
+ if ($album === '.' || $album === '..' || !is_dir($dir . $album)) continue;
+ $albums[$album] = [
+ 'protected' => isset($passwords[$album]) && $passwords[$album] !== '',
+ ];
+ }
}
header('Content-Type: application/json');
-echo json_encode($images);
+echo json_encode($albums);
?>
\ No newline at end of file
diff --git a/passwords.json b/passwords.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/passwords.json
@@ -0,0 +1 @@
+{}