diff --git a/.gitignore b/.gitignore
index 36ad86f14..33ead8c0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ config/
env.json
variables.json
html/allsky/configuration.json
+html/allsky/images/[0-9][0-9][0-9][0-9]/
html/allsky/viewSettings/
scripts/allsky-config
scripts/functions.php
diff --git a/config_repo/options.json.repo b/config_repo/options.json.repo
index cb7232e58..5c4be594e 100644
--- a/config_repo/options.json.repo
+++ b/config_repo/options.json.repo
@@ -1475,6 +1475,16 @@
"booldependson" : "timelapsegenerate AND timelapseupload AND (uselocalwebsite OR useremotewebsite OR useremoteserver)"
},
{
+"name" : "uploadimages",
+"default" : false,
+"description" : "Enable to upload all images from the day to an Allsky Website and/or remote server in images/YYYY/YYYYMMDD/ format.",
+"label" : "Upload Images",
+"label_prefix" : "Daily Timelapse",
+"type" : "boolean",
+"carryforward" : true,
+"booldependson" : "timelapsegenerate AND (uselocalwebsite OR useremotewebsite OR useremoteserver)"
+},
+{
"name" : "keogramupload",
"default" : true,
"description" : "Enable to upload the keogram to an Allsky Website and/or remote server.",
diff --git a/html/allsky/images/index.php b/html/allsky/images/index.php
new file mode 100644
index 000000000..6ccf08ed4
--- /dev/null
+++ b/html/allsky/images/index.php
@@ -0,0 +1,202 @@
+
+
+
+
+
+
+
+
+
+";
+ }
+?>
+
+
+
+
+
+
+modify('-1 day');
+$next_date = clone $date_obj;
+$next_date->modify('+1 day');
+
+$year = substr($selected_date, 0, 4);
+$month = substr($selected_date, 4, 2);
+$day = substr($selected_date, 6, 2);
+$formatted_date = "$year-$month-$day ({$date_obj->format('l')})";
+
+// Build directory path
+$dir = "./$year/$selected_date";
+
+// Get list of images
+$images = array();
+if (is_dir($dir)) {
+ $files = glob("$dir/*.{jpg,JPG,jpeg,JPEG}", GLOB_BRACE);
+ foreach ($files as $file) {
+ $images[] = basename($file);
+ }
+
+ if ($thumbnailsortorder === "descending") {
+ arsort($images);
+ } else {
+ asort($images);
+ }
+}
+
+$num_images = count($images);
+?>
+
+
+
+
+
+
+
+
+
+
+ ( images)
+
+
+$back_button";
+ echo "No images for $formatted_date
";
+} else {
+ echo "";
+
+ // Try to create thumbnails directory
+ $thumb_dir = "$dir/thumbnails";
+ $can_create_thumbs = false;
+ if (is_dir($thumb_dir)) {
+ $can_create_thumbs = true;
+ } else {
+ // Try to create with recursive flag
+ if (@mkdir($thumb_dir, 0775, true)) {
+ $can_create_thumbs = true;
+ }
+ }
+
+ echo "\n";
+
+ foreach ($images as $image) {
+ $image_path = "$dir/$image";
+ $thumbnail = "$thumb_dir/$image";
+
+ // Use thumbnail if exists, otherwise try to create it, or use full image
+ if (file_exists($thumbnail)) {
+ $display_image = $thumbnail;
+ } else if ($can_create_thumbs && make_thumb($image_path, $thumbnail, $thumbnailSizeX)) {
+ $display_image = $thumbnail;
+ flush();
+ } else {
+ // Can't create thumbnail, use full image
+ $display_image = $image_path;
+ }
+
+ // Extract time from filename (YYYYMMDD_HHMMSS.jpg)
+ $time = '';
+ if (preg_match('/\d{8}_(\d{2})(\d{2})(\d{2})/', $image, $matches)) {
+ $time = $matches[1] . ':' . $matches[2] . ':' . $matches[3];
+ }
+
+ echo "
";
+ echo "
";
+ echo "

";
+ echo "
";
+ echo "
$time
";
+ echo "
\n";
+ }
+
+ echo "
"; // archived-files
+ echo "";
+ echo "
";
+}
+?>
+
+
+
+
+
diff --git a/html/includes/days.php b/html/includes/days.php
index 58bc851f5..31d3b62df 100644
--- a/html/includes/days.php
+++ b/html/includes/days.php
@@ -102,8 +102,17 @@ function ListDays()
$i = getValidImageNames(ALLSKY_IMAGES . "/$day/meteors", true); // true == stop after 1
$has_meteors = (count($i) > 0);
}
+ // Check for archived images in images/YYYY/YYYYMMDD/
+ $year = substr($day, 0, 4);
+ $archived_dir = ALLSKY_IMAGES . "/images/$year/$day";
+ $has_archived_images = false;
+ if (is_dir($archived_dir)) {
+ $ai = getValidImageNames($archived_dir, true); // true == stop after 1
+ $has_archived_images = (count($ai) > 0);
+ }
+
- if (! $has_images && ! $has_timelapse && ! $has_keogram && ! $has_startrails && ! $has_meteors) {
+ if (! $has_images && ! $has_timelapse && ! $has_keogram && ! $has_startrails && ! $has_meteors && ! $has_archived_images) {
echo "";
continue;
}
@@ -119,6 +128,10 @@ function ListDays()
echo "none";
}
echo "\n";
+ if ($has_archived_images) {
+ $icon_archive = "";
+ echo " $icon_archive";
+ }
echo "\t\t\t";
if ($has_timelapse) {
diff --git a/html/includes/images.php b/html/includes/images.php
index 5729b553c..27746795a 100644
--- a/html/includes/images.php
+++ b/html/includes/images.php
@@ -32,7 +32,22 @@ function ListImages() {
return;
}
- $dir = ALLSKY_IMAGES . "/$chosen_day";
+ // Check if we should display archived images
+ $archived = getVariableOrDefault($_GET, 'archived', 0);
+
+ if ($archived == 1) {
+ // Display from images/YYYY/YYYYMMDD/
+ $year = substr($chosen_day, 0, 4);
+ $dir = ALLSKY_IMAGES . "/images/$year/$chosen_day";
+ $web_path = "/images/images/$year/$chosen_day";
+ $title_suffix = " (Archived)";
+ } else {
+ // Display from regular day directory
+ $dir = ALLSKY_IMAGES . "/$chosen_day";
+ $web_path = "/images/$chosen_day";
+ $title_suffix = "";
+ }
+
$images = getValidImageNames($dir, false); // false == get whole list
if (count($images) > 0) {
if ($imagesSortOrder === "descending") {
@@ -48,7 +63,7 @@ function ListImages() {
}
if (count($images) == 0) {
- DisplayImageError("Displaying images", "There are no images for $chosen_day");
+ DisplayImageError("Displaying images", "There are no images for $chosen_day$title_suffix");
}
$width = getVariableOrDefault($settings_array, 'thumbnailsizex', 100);
@@ -57,8 +72,8 @@ function ListImages() {
echo '';
foreach ($images as $image) {
- echo " ";
- echo " ";
+ echo "";
+ echo " ";
echo '';
}
@@ -88,4 +103,4 @@ function ListImages() {
}
-?>
\ No newline at end of file
+?>
diff --git a/scripts/saveImage.sh b/scripts/saveImage.sh
index 2d8136cde..2dae76d13 100755
--- a/scripts/saveImage.sh
+++ b/scripts/saveImage.sh
@@ -488,6 +488,89 @@ if [[ ${IMG_UPLOAD_FREQUENCY} -gt 0 ]]; then
fi
fi
+
+# Upload archived images to remote website if enabled
+if [[ ${S_uploadimages} == "true" && ${SAVE_IMAGE} == "true" && ${IMG_UPLOAD_FREQUENCY} -gt 0 ]]; then
+ # Check if we should upload this image based on frequency
+ UPLOAD_COUNTER_FILE="${ALLSKY_TMP}/image_upload_counter.txt"
+ if [[ ! -f ${UPLOAD_COUNTER_FILE} ]]; then
+ echo "0" > "${UPLOAD_COUNTER_FILE}"
+ fi
+ UPLOAD_COUNTER=$(<"${UPLOAD_COUNTER_FILE}")
+ UPLOAD_COUNTER=$((UPLOAD_COUNTER + 1))
+
+ if [[ ${UPLOAD_COUNTER} -ge ${IMG_UPLOAD_FREQUENCY} ]]; then
+ echo "0" > "${UPLOAD_COUNTER_FILE}"
+
+ # Extract year from DATE_NAME (first 4 characters: YYYYMMDD -> YYYY)
+ YEAR="${DATE_NAME:0:4}"
+ REMOTE_IMAGE_DIR="images/${YEAR}/${DATE_NAME}"
+ IMAGE_BASENAME="$(basename "${CURRENT_IMAGE}")"
+
+ # Try to upload the image directly
+ UPLOAD_SUCCESS="false"
+ if upload_all --remote-web "${CURRENT_IMAGE}" "${REMOTE_IMAGE_DIR}" "${IMAGE_BASENAME}" "ArchivedImage" 2>/dev/null; then
+ if upload_all --remote-server "${CURRENT_IMAGE}" "${REMOTE_IMAGE_DIR}" "${IMAGE_BASENAME}" "ArchivedImage" 2>/dev/null; then
+ UPLOAD_SUCCESS="true"
+ fi
+ fi
+
+ # If upload failed, add to queue
+ if [[ ${UPLOAD_SUCCESS} == "false" ]]; then
+ # Check RAMFS available space before saving to queue
+ RAMFS_AVAILABLE=$(df -k "${ALLSKY_TMP}" | tail -1 | awk '{print $4}')
+ RAMFS_THRESHOLD=102400 # 100MB in KB
+
+ if [[ ${RAMFS_AVAILABLE} -lt ${RAMFS_THRESHOLD} ]]; then
+ # Not enough space, log alert
+ ALERT_MSG="$(date '+%Y-%m-%d %H:%M:%S') - WARNING: RAMFS space below 100MB threshold (${RAMFS_AVAILABLE} KB available). Cannot queue image upload."
+ echo "${ALERT_MSG}" >> "${ALLSKY_TMP}/image_upload_alerts.log"
+ echo "${ALERT_MSG}" >&2
+
+ # Call allskyNotify.sh if available
+ if [[ -x "${ALLSKY_SCRIPTS}/allskyNotify.sh" ]]; then
+ "${ALLSKY_SCRIPTS}/allskyNotify.sh" "WARNING" "RAMFS space low" "${ALERT_MSG}"
+ fi
+ else
+ # Enough space, save to queue
+ QUEUE_DIR="${ALLSKY_TMP}/image_upload_queue/${YEAR}/${DATE_NAME}"
+ mkdir -p "${QUEUE_DIR}"
+ cp "${CURRENT_IMAGE}" "${QUEUE_DIR}/${IMAGE_BASENAME}"
+ fi
+ fi
+ else
+ echo "${UPLOAD_COUNTER}" > "${UPLOAD_COUNTER_FILE}"
+ fi
+
+ # Process the retry queue
+ QUEUE_BASE="${ALLSKY_TMP}/image_upload_queue"
+ if [[ -d ${QUEUE_BASE} ]]; then
+ # Find all queued images and try to upload them
+ while IFS= read -r -d '' QUEUED_IMAGE; do
+ # Extract path components: queue/YYYY/YYYYMMDD/filename.jpg
+ RELATIVE_PATH="${QUEUED_IMAGE#${QUEUE_BASE}/}"
+ QUEUE_YEAR="$(echo "${RELATIVE_PATH}" | cut -d'/' -f1)"
+ QUEUE_DATE="$(echo "${RELATIVE_PATH}" | cut -d'/' -f2)"
+ QUEUE_FILENAME="$(basename "${QUEUED_IMAGE}")"
+ QUEUE_REMOTE_DIR="images/${QUEUE_YEAR}/${QUEUE_DATE}"
+
+ # Try to upload
+ if upload_all --remote-web "${QUEUED_IMAGE}" "${QUEUE_REMOTE_DIR}" "${QUEUE_FILENAME}" "QueuedImage" 2>/dev/null; then
+ if upload_all --remote-server "${QUEUED_IMAGE}" "${QUEUE_REMOTE_DIR}" "${QUEUE_FILENAME}" "QueuedImage" 2>/dev/null; then
+ # Upload successful, remove from queue
+ rm -f "${QUEUED_IMAGE}"
+
+ # Remove empty directories
+ QUEUE_DATE_DIR="${QUEUE_BASE}/${QUEUE_YEAR}/${QUEUE_DATE}"
+ QUEUE_YEAR_DIR="${QUEUE_BASE}/${QUEUE_YEAR}"
+ [[ -d ${QUEUE_DATE_DIR} ]] && rmdir --ignore-fail-on-non-empty "${QUEUE_DATE_DIR}"
+ [[ -d ${QUEUE_YEAR_DIR} ]] && rmdir --ignore-fail-on-non-empty "${QUEUE_YEAR_DIR}"
+ fi
+ fi
+ done < <(find "${QUEUE_BASE}" -type f -name "*.jpg" -print0)
+ fi
+fi
+
# If needed, upload the mini timelapse. If the upload failed above, it will likely fail below.
if [[ ${TIMELAPSE_MINI_UPLOAD_VIDEO} == "true" && ${SAVE_IMAGE} == "true" && ${RET} -eq 0 ]] ; then
FILE_TO_UPLOAD="${ALLSKY_MINITIMELAPSE_FILE}"
|