fine tuning and readme
parent
b18605004b
commit
d551023e56
@ -0,0 +1,108 @@
|
|||||||
|
# archiepixa
|
||||||
|
|
||||||
|
|
||||||
|
`archiepixa` is a minimalist Bash script designed to visualize archives with a webserver. It scans a specified folder and its subfolders, compresses previews using `ffmpeg` and `imagemagick`, and compiles them into HTML files, one for each subfolder.
|
||||||
|
|
||||||
|
The code has been developed for the workshop *[Building collective digital archives]("https://dsignweek.servus.at/program/fri-24/building-collective-digital-archives/")* during the [D*sign Week 2024, Linz]("https://dsignweek.servus.at/"). Powered by [Servus]("https://servus.at")
|
||||||
|
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
- Scans specified folder and subfolders for files
|
||||||
|
- Compresses previews for images, videos, and audio files
|
||||||
|
- Generates static HTML files with customizable CSS styling
|
||||||
|
- Customization of main color, secondary color, background color, and footer text
|
||||||
|
|
||||||
|
|
||||||
|
## System Requirements
|
||||||
|
|
||||||
|
- Bash shell
|
||||||
|
- `ffmpeg` and `imagemagick` packages for media file compression
|
||||||
|
|
||||||
|
## Installation Instructions
|
||||||
|
|
||||||
|
### Installing ffmpeg and imagemagick
|
||||||
|
|
||||||
|
To install `ffmpeg` and `imagemagick`, use the package manager specific to your operating system.
|
||||||
|
|
||||||
|
#### For Ubuntu/Debian:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get install ffmpeg imagemagick
|
||||||
|
```
|
||||||
|
|
||||||
|
#### For macOS (using Homebrew):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install ffmpeg imagemagick
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To use `archiepixa`, follow these steps:
|
||||||
|
|
||||||
|
1. Place `archiepixa.sh` in the parent folder of the directory you want to scan.
|
||||||
|
2. Run the script using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash archiepixa.sh -f <folder_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `<folder_name>` with the name of the folder you want to scan.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
A practical example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/html/
|
||||||
|
git clone http://git.servus.at/servus/archiepixa
|
||||||
|
mv archiepixa/archipiexa.sh ./
|
||||||
|
bash archiepixa.sh -f ""
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
You can customize the appearance of the generated HTML files by modifying the **CSS** within the Bash script.
|
||||||
|
|
||||||
|
You can use flags to modify the background, the main, the second, the third color and you can choose how many colors the dither uses.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash archiepixa.sh -f "folder" -b "black" -1 "purple" -2 "rgb('22','45','223')" -3 "#342298" -d "5"
|
||||||
|
```
|
||||||
|
|
||||||
|
Defaults are:
|
||||||
|
|
||||||
|
* -1 "red"
|
||||||
|
* -2 "orange"
|
||||||
|
* -3 "black"
|
||||||
|
* -b "white"
|
||||||
|
* -d "3"
|
||||||
|
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
|
|
||||||
|
To remove the generated HTML files, use the `-r` flag along with the folder name:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash archiepixa.sh -f <folder_name> -r
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete both the HTML files and compressed folders, use the `-ra` flag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash archiepixa.sh -f <folder_name> -ra
|
||||||
|
```
|
||||||
|
|
||||||
|
## IMPORTANT!
|
||||||
|
|
||||||
|
**Note:** Avoid placing files named "index.html" within the scanned folders to prevent conflicts.
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This script is licensed under the [Habitat License](https://habitattt.it/license).
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
@ -0,0 +1,376 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
main_folder="poni"
|
||||||
|
main="red"
|
||||||
|
second="orange"
|
||||||
|
third="black"
|
||||||
|
background="white"
|
||||||
|
n_colors_dither="3"
|
||||||
|
footer=""
|
||||||
|
|
||||||
|
# Parse command line options
|
||||||
|
while getopts ":f:1:2:3:d:b:foot" opt; do
|
||||||
|
case ${opt} in
|
||||||
|
f )
|
||||||
|
main_folder="$OPTARG"
|
||||||
|
;;
|
||||||
|
1 )
|
||||||
|
main="$OPTARG"
|
||||||
|
;;
|
||||||
|
2 )
|
||||||
|
second="$OPTARG"
|
||||||
|
;;
|
||||||
|
3 )
|
||||||
|
third="$OPTARG"
|
||||||
|
;;
|
||||||
|
d )
|
||||||
|
n_colors_dither="$OPTARG"
|
||||||
|
;;
|
||||||
|
b )
|
||||||
|
background="$OPTARG"
|
||||||
|
;;
|
||||||
|
foot )
|
||||||
|
footer="$OPTARG"
|
||||||
|
;;
|
||||||
|
\? )
|
||||||
|
echo "Invalid option: $OPTARG" 1>&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
: )
|
||||||
|
echo "Invalid option: $OPTARG requires an argument" 1>&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND -1))
|
||||||
|
|
||||||
|
css='
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'arial';
|
||||||
|
background-color: var(--bck)
|
||||||
|
}
|
||||||
|
|
||||||
|
h1{
|
||||||
|
font-weight: 100;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--main);
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 3rem;
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2{
|
||||||
|
color: var(--second);
|
||||||
|
}
|
||||||
|
|
||||||
|
a{
|
||||||
|
text-align: center;
|
||||||
|
color: var(--second);
|
||||||
|
}
|
||||||
|
|
||||||
|
li a{
|
||||||
|
color: var(--third);
|
||||||
|
}
|
||||||
|
|
||||||
|
header,footer p{
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
color: var(--second);
|
||||||
|
font-size: 2rem
|
||||||
|
}
|
||||||
|
|
||||||
|
footer{
|
||||||
|
border-top: solid var(--main);
|
||||||
|
bottom: 0;
|
||||||
|
position: fixed;
|
||||||
|
margin-top: 2rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: var(--bck);
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p{
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--third);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a{
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception{
|
||||||
|
color: var(--main)
|
||||||
|
}
|
||||||
|
|
||||||
|
hr{
|
||||||
|
color: var(--main);
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go{
|
||||||
|
max-width: 75%;
|
||||||
|
gap: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
line-height: .5;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go a{
|
||||||
|
margin-right: 1.5rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents{
|
||||||
|
margin-bottom: 10%;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 10%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents div{
|
||||||
|
padding: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
img, video {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.contents{
|
||||||
|
margin-bottom: 50%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents div{
|
||||||
|
gap: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go{
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
width: 70%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
'
|
||||||
|
|
||||||
|
# Function to compress and generate HTML links
|
||||||
|
compress_and_generate_links() {
|
||||||
|
|
||||||
|
local folder="$1"
|
||||||
|
local compressed_folder="compressed"
|
||||||
|
mkdir -p "$folder"/"$compressed_folder"
|
||||||
|
|
||||||
|
declare -a text_files
|
||||||
|
declare -a picture_files
|
||||||
|
declare -a video_files
|
||||||
|
declare -a audio_files
|
||||||
|
declare -a other_files
|
||||||
|
|
||||||
|
for file in "$folder"/*; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
case "$file" in
|
||||||
|
*.txt|*.md|*.html|*.sh|*.py|*.js|*.php|*.TXT|*.MD)
|
||||||
|
text_files+=("$file")
|
||||||
|
;;
|
||||||
|
*.jpg|*.png|*.heic|*.svg|*.JPG|*.PNG|*.HEIC|*.SVG)
|
||||||
|
picture_files+=("$file")
|
||||||
|
;;
|
||||||
|
# |*.gif|*.GIF)
|
||||||
|
# gif_files+=("$file")
|
||||||
|
# ;;
|
||||||
|
*.mp4|*.mov|*.mkv|*.avi|*.MP4|*.M)
|
||||||
|
video_files+=("$file")
|
||||||
|
;;
|
||||||
|
*.mp3|*.wav|*.WAV|*.aiff|*.AIFF|*.FLAC|*.MP3|*.flac)
|
||||||
|
audio_files+=("$file")
|
||||||
|
;;
|
||||||
|
*index.html) # Exclude index.html files
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
other_files+=("$file")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create index.html file
|
||||||
|
index_file="$folder/index.html"
|
||||||
|
echo "<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>$folder</title>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
:root{
|
||||||
|
--main: $main;
|
||||||
|
--second: $second;
|
||||||
|
--third: $third;
|
||||||
|
--bck: $background;
|
||||||
|
}
|
||||||
|
|
||||||
|
$css
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>" > "$index_file"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Header Wrappers
|
||||||
|
echo "<header>" >> "$index_file"
|
||||||
|
|
||||||
|
# Add links to subfolders with their names displayed
|
||||||
|
subfolders=()
|
||||||
|
for subfolder in "$folder"/*; do
|
||||||
|
if [ -d "$subfolder" ] && [ ! "$(basename "$subfolder")" == "compressed" ]; then
|
||||||
|
subfolder_name=$(basename "$subfolder")
|
||||||
|
subfolders+=("<a href=\"$subfolder_name\">⟿ $subfolder_name</a>")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Open the header
|
||||||
|
echo "<div class='go'>" >> "$index_file"
|
||||||
|
|
||||||
|
if [ ${#subfolders[@]} -gt 0 ]; then
|
||||||
|
echo "" >> "$index_file"
|
||||||
|
for subfolder_link in "${subfolders[@]}"; do
|
||||||
|
echo "$subfolder_link" >> "$index_file"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Close the header
|
||||||
|
echo "</div>" >> "$index_file"
|
||||||
|
|
||||||
|
# Add the possibility to go back from the page
|
||||||
|
if [ ! "$(basename "$folder")" == "$(basename "$main_folder")" ]; then
|
||||||
|
echo "<p class="back"><a class="arrow_back" href='../'>⬳</a></p>" >> "$index_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Header Wrappers
|
||||||
|
echo "</header>" >> "$index_file"
|
||||||
|
|
||||||
|
echo "<h1>$folder</h1><div class='contents'>" >> "$index_file"
|
||||||
|
|
||||||
|
# Display text files in the subfolder
|
||||||
|
if [ ${#text_files[@]} -gt 0 ]; then
|
||||||
|
echo "<div class='text'>" >> "$index_file"
|
||||||
|
for text_file in "${text_files[@]}"; do
|
||||||
|
echo "<div><a href=\"$text_file\" target=\"_blank\">$text_file</a><br><p></p></div>" >> "$index_file"
|
||||||
|
done
|
||||||
|
echo "</div>" >> "$index_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compress and display picture files in the subfolder
|
||||||
|
if [ ${#picture_files[@]} -gt 0 ]; then
|
||||||
|
# echo "<div class='pics'>" >> "$index_file"
|
||||||
|
for picture_file in "${picture_files[@]}"; do
|
||||||
|
compressed_file="$folder"/"$compressed_folder/$(basename "$picture_file")_compressed.jpg"
|
||||||
|
if [ ! -f "$compressed_file" ]; then
|
||||||
|
if $dither; then
|
||||||
|
convert "$picture_file" -dither Riemersma -colors $n_colors_dither -quality 85 "$compressed_file"
|
||||||
|
else
|
||||||
|
convert "$picture_file" -quality 85 "$compressed_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "<div>
|
||||||
|
<a href="\"/$compressed_file"\"><img loading=\"lazy\" src=\"/$compressed_file\" alt=\"Compressed Image\"></a>
|
||||||
|
<a href=\"$(basename "$picture_file")\" target=\"_blank\">Original ⇝ $(basename "$picture_file")</a>
|
||||||
|
</div>" >> "$index_file"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compress and display video files in the subfolder
|
||||||
|
if [ ${#video_files[@]} -gt 0 ]; then
|
||||||
|
# echo "<div class='vids'>" >> "$index_file"
|
||||||
|
for video_file in "${video_files[@]}"; do
|
||||||
|
compressed_file="$folder"/"$compressed_folder/$(basename "$video_file")_compressed.mp4"
|
||||||
|
if [ ! -f "$compressed_file" ]; then
|
||||||
|
ffmpeg -i "$video_file" -vf "scale=640:480" -c:v libx264 -crf 23 -c:a aac -strict experimental "$compressed_file" -y
|
||||||
|
fi
|
||||||
|
echo "<div>
|
||||||
|
<video controls>
|
||||||
|
<source src=\"/$compressed_file\" type=\"video/mp4\">
|
||||||
|
</video>
|
||||||
|
<a href=\"$(basename "$video_file")\" target=\"_blank\">Original ⇝ $(basename "$video_file")</a>
|
||||||
|
</div>" >> "$index_file"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compress and display audio files in the subfolder
|
||||||
|
if [ ${#audio_files[@]} -gt 0 ]; then
|
||||||
|
for audio_file in "${audio_files[@]}"; do
|
||||||
|
compressed_file="$folder"/"$compressed_folder/$(basename "$audio_file")_compressed.mp3"
|
||||||
|
if [ ! -f "$compressed_file" ]; then
|
||||||
|
ffmpeg -i "$audio_file" -b:a 96k "$compressed_file" -y
|
||||||
|
fi
|
||||||
|
echo "<div>
|
||||||
|
<audio controls>
|
||||||
|
<source src=\"/$compressed_file\" type=\"audio/mpeg\">
|
||||||
|
</audio>
|
||||||
|
<a href=\"$(basename "$audio_file")\" target=\"_blank\">Original ⇝ $(basename "$audio_file")</a>
|
||||||
|
</div>" >> "$index_file"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display other files in the subfolder
|
||||||
|
if [ ${#other_files[@]} -gt 0 ]; then
|
||||||
|
echo "<hr><div class="others"><h2>Other Files:</h2><ul>" >> "$index_file"
|
||||||
|
for other_file in "${other_files[@]}"; do
|
||||||
|
echo "<li><a href=\"$(basename "$other_file")\" target=\"_blank\">$other_file</a></li>" >> "$index_file"
|
||||||
|
done
|
||||||
|
echo "</ul></div>" >> "$index_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Close HTML tags
|
||||||
|
echo "</div>
|
||||||
|
<footer>$footer</footer>
|
||||||
|
</body></html>" >> "$index_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to iterate through all subfolders excluding "compressed"
|
||||||
|
function iterate_subfolders() {
|
||||||
|
local folder="$1"
|
||||||
|
|
||||||
|
# Loop through each item in the folder
|
||||||
|
for item in "$folder"/*; do
|
||||||
|
# Check if the item is a directory
|
||||||
|
if [ -d "$item" ] && [ ! "$(basename "$item")" == "compressed" ] && [ ! "$(basename "$item")" == "*" ]; then
|
||||||
|
compress_and_generate_links "$item"
|
||||||
|
iterate_subfolders "$item"
|
||||||
|
echo "$item"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
compress_and_generate_links "$main_folder"
|
||||||
|
|
||||||
|
# Start iterating from the main folder
|
||||||
|
iterate_subfolders $main_folder
|
||||||
|
|
||||||
|
|
||||||
|
echo "HTML files created for each subfolder."
|
Loading…
Reference in New Issue