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 @@ + + + + + + + + <?php echo $title; ?> + +"; + } +?> + + + + + + +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 ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "
$back_button$title - $formatted_date
$num_images images - "; + echo ($thumbnailsortorder === "descending") ? "Sorted newest to oldest" : "Sorted oldest to newest"; + 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 " $image"; + echo ""; + echo " $image"; 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}"