diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3c44241 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/workflows/optimize-and-deploy.yml b/.github/workflows/optimize-and-deploy.yml new file mode 100644 index 0000000..5053b9f --- /dev/null +++ b/.github/workflows/optimize-and-deploy.yml @@ -0,0 +1,38 @@ +name: Optimize and Deploy + +on: + push: + branches: + - main + +jobs: + optimize: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y webp librsvg2-bin + + - name: Optimization + run: | + ./optimize.sh -h tracks 600 -q 100 -o out + ./optimize.sh -i artists -h 320 -q 100 -o out + + - name: Deploy + run: | + sudo chown -R $(whoami):$(whoami) . + git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" + git config --global user.name "$GITHUB_ACTOR" + cp -r out/* /tmp + cd /tmp + git init + git branch -M gh-pages + git add . + git commit -m "Optimize images" + git remote add origin "https://$GITHUB_ACTOR:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY" + git push -f origin gh-pages diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ceb386 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv diff --git a/artists/adele.jpeg b/artists/adele.jpeg new file mode 100644 index 0000000..ca0847e Binary files /dev/null and b/artists/adele.jpeg differ diff --git a/artists/akon.jpeg b/artists/akon.jpeg new file mode 100644 index 0000000..392c6fe Binary files /dev/null and b/artists/akon.jpeg differ diff --git a/artists/alok.jpeg b/artists/alok.jpeg new file mode 100644 index 0000000..8e75ac5 Binary files /dev/null and b/artists/alok.jpeg differ diff --git a/artists/arctic_monkeys.jpeg b/artists/arctic_monkeys.jpeg new file mode 100644 index 0000000..547797a Binary files /dev/null and b/artists/arctic_monkeys.jpeg differ diff --git a/artists/bruno_mars.jpeg b/artists/bruno_mars.jpeg new file mode 100644 index 0000000..d5b2009 Binary files /dev/null and b/artists/bruno_mars.jpeg differ diff --git a/artists/cyndi_lauper.jpeg b/artists/cyndi_lauper.jpeg new file mode 100644 index 0000000..593b866 Binary files /dev/null and b/artists/cyndi_lauper.jpeg differ diff --git a/artists/ed_sheeran.jpeg b/artists/ed_sheeran.jpeg new file mode 100644 index 0000000..d538868 Binary files /dev/null and b/artists/ed_sheeran.jpeg differ diff --git a/artists/george_michael.jpeg b/artists/george_michael.jpeg new file mode 100644 index 0000000..bc69a8d Binary files /dev/null and b/artists/george_michael.jpeg differ diff --git a/artists/gotye.jpeg b/artists/gotye.jpeg new file mode 100644 index 0000000..3842565 Binary files /dev/null and b/artists/gotye.jpeg differ diff --git a/artists/justin_bieber.jpeg b/artists/justin_bieber.jpeg new file mode 100644 index 0000000..bb40c69 Binary files /dev/null and b/artists/justin_bieber.jpeg differ diff --git a/artists/justin_timberlake.jpeg b/artists/justin_timberlake.jpeg new file mode 100644 index 0000000..5d6753a Binary files /dev/null and b/artists/justin_timberlake.jpeg differ diff --git a/artists/keane.jpeg b/artists/keane.jpeg new file mode 100644 index 0000000..3c4f880 Binary files /dev/null and b/artists/keane.jpeg differ diff --git a/artists/lewis_capaldi.jpeg b/artists/lewis_capaldi.jpeg new file mode 100644 index 0000000..75b9423 Binary files /dev/null and b/artists/lewis_capaldi.jpeg differ diff --git a/artists/maroon_5.jpeg b/artists/maroon_5.jpeg new file mode 100644 index 0000000..3f59c25 Binary files /dev/null and b/artists/maroon_5.jpeg differ diff --git a/artists/marshmello.jpeg b/artists/marshmello.jpeg new file mode 100644 index 0000000..13f05de Binary files /dev/null and b/artists/marshmello.jpeg differ diff --git a/artists/no_copyright_music_sounds.jpeg b/artists/no_copyright_music_sounds.jpeg new file mode 100644 index 0000000..2cecdf1 Binary files /dev/null and b/artists/no_copyright_music_sounds.jpeg differ diff --git a/artists/nocopyrightsounds.jpeg b/artists/nocopyrightsounds.jpeg new file mode 100644 index 0000000..2cecdf1 Binary files /dev/null and b/artists/nocopyrightsounds.jpeg differ diff --git a/artists/radiohead.jpeg b/artists/radiohead.jpeg new file mode 100644 index 0000000..698d526 Binary files /dev/null and b/artists/radiohead.jpeg differ diff --git a/artists/rick_astley.jpeg b/artists/rick_astley.jpeg new file mode 100644 index 0000000..7f41b6b Binary files /dev/null and b/artists/rick_astley.jpeg differ diff --git a/artists/the_neighbourhood.jpeg b/artists/the_neighbourhood.jpeg new file mode 100644 index 0000000..6affc8b Binary files /dev/null and b/artists/the_neighbourhood.jpeg differ diff --git a/artists/the_weeknd.jpeg b/artists/the_weeknd.jpeg new file mode 100644 index 0000000..dad8430 Binary files /dev/null and b/artists/the_weeknd.jpeg differ diff --git a/download.py b/download.py new file mode 100644 index 0000000..fe7ecc6 --- /dev/null +++ b/download.py @@ -0,0 +1,130 @@ +import os +import re +import requests +from unidecode import unidecode + +client_id = 'abdf2b61efc64653b5f03d643a672f2a' +client_secret = '9446410f052f4a1d88eb31e56edf3fbe' + +auth_response = requests.post('https://accounts.spotify.com/api/token', { + 'grant_type': 'client_credentials', + 'client_id': client_id, + 'client_secret': client_secret, +}) + +auth_response_data = auth_response.json() +access_token = auth_response_data['access_token'] + +headers = { + 'Authorization': f'Bearer {access_token}', +} + + +def main(): + while True: + print('1 - Track') + print('2 - Artist') + print('3 - Exit') + + try: + option = int(input('Option: ')) + except ValueError: + print('Invalid option') + continue + + match option: + case 1: + download_album_image(input('Track: ')) + case 2: + download_artist_image(input('Artist: ')) + case 3: + exit(0) + case _: + print('Invalid option') + + +def download_album_image(track_name): + search_response = requests.get( + 'https://api.spotify.com/v1/search', + headers=headers, + params={ + 'q': track_name, + 'type': 'track', + 'limit': 1 + } + ) + + search_data = search_response.json() + + try: + album = search_data['tracks']['items'][0]['album'] + image_url = album['images'][0]['url'] + album_name = album['name'] + except (KeyError, IndexError): + print(f'No album image found for track: {track_name}') + return + + filename = jpeg_filename(album_name) + save_path = os.path.join('tracks', filename) + + if not os.path.exists(save_path): + response = requests.get(image_url) + if response.status_code == 200: + os.makedirs('tracks', exist_ok=True) + with open(save_path, 'wb') as file: + file.write(response.content) + print(f'{filename} download completed.') + else: + print(f'Failed to download image for track: {track_name}') + else: + print(f'{filename} already exists.') + + +def download_artist_image(artist_name): + filename = jpeg_filename(artist_name) + save_path = os.path.join('artists', filename) + + if not os.path.exists(save_path): + search_response = requests.get( + 'https://api.spotify.com/v1/search', + headers=headers, + params={ + 'q': artist_name, + 'type': 'artist', + 'limit': 1 + } + ) + + search_data = search_response.json() + + try: + image_url = search_data['artists']['items'][0]['images'][0]['url'] + artist_name = search_data['artists']['items'][0]['name'] + except (KeyError, IndexError): + print(f'No image found for artist: {artist_name}') + return + + response = requests.get(image_url) + if response.status_code == 200: + os.makedirs('artists', exist_ok=True) + with open(save_path, 'wb') as file: + file.write(response.content) + print(f'{filename} download completed.') + else: + print(f'Failed to download image for artist: {artist_name}') + else: + print(f'{filename} already exists.') + + +def jpeg_filename(name): + return f'{snake_case(name)}.jpeg' + + +def snake_case(text): + text = unidecode(text.strip().lower()) + text = re.sub(r'\s+', '_', text) + return re.sub(r'[^\w_]', '', text) + + +if __name__ == '__main__': + main() diff --git a/optimize.sh b/optimize.sh new file mode 100644 index 0000000..3c29ade --- /dev/null +++ b/optimize.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +TEMP_DIR=temp +INPUT_DIR=src +OUTPUT_DIR=out + +WIDTH=0 +HEIGHT=300 +IMAGE_QUALITY=100 + +while getopts ":o:w:h:q:" opt; do + case ${opt} in + i ) + INPUT_DIR=$OPTARG + ;; + o ) + OUTPUT_DIR=$OPTARG + ;; + w ) + WIDTH=$OPTARG + ;; + h ) + HEIGHT=$OPTARG + ;; + q ) + IMAGE_QUALITY=$OPTARG + ;; + \? ) + echo "Usage: ./optimize.sh [-i input_dir] [-o output_dir] [-w width] [-h height] [-q image_quality]" + exit 1 + ;; + esac +done + +rm -rf "$TEMP_DIR" +mkdir -p "$OUTPUT_DIR" + +mkdir "$TEMP_DIR" +cp -r "$INPUT_DIR"/* "$TEMP_DIR" + +optimize_image() { + local input_file="$1" + local output_file="$2" + cwebp -q "$IMAGE_QUALITY" -m 6 -sharpness 0 -noalpha -resize "$WIDTH" "$HEIGHT" -quiet "$input_file" -o "$output_file" +} + +convert_svg_to_webp() { + local input_file="$1" + local output_file="$2" + local temp_png="${output_file}.png" + rsvg-convert -o "$temp_png" "$input_file" + optimize_image "$temp_png" "$output_file" + rm "$temp_png" +} + +optimize_webp() { + local input_file="$1" + local output_file="$2" + local temp_output="${output_file}.temp" + + if webpmux -info "$input_file" 2>&1 | grep -q "No. of frames: 1"; then + optimize_image "$input_file" "$temp_output" + else + gif2webp -q "$IMAGE_QUALITY" "$input_file" -o "$temp_output" + fi + + local original_size=$(stat -c %s "$input_file") + local new_size=$(stat -c %s "$temp_output") + + if (( new_size < original_size )); then + mv "$temp_output" "$output_file" + echo "Optimized: $input_file -> $output_file (reduced size from $original_size to $new_size)" + else + rm "$temp_output" + cp "$input_file" "$output_file" + echo "Copied without change: $input_file -> $output_file" + fi +} + +file_exists_in_output() { + local input_file="$1" + local filename=$(basename "$input_file") + [ -f "$OUTPUT_DIR/$filename" ] +} + +process_images() { + for img in "$TEMP_DIR"/*.{jpg,jpeg,png}; do + [ -f "$img" ] || continue + filename=$(basename "$img" .${img##*.}) + output_file="$OUTPUT_DIR/$filename.webp" + if ! file_exists_in_output "$output_file"; then + optimize_image "$img" "$output_file" + echo "Converted: $img -> $output_file" + fi + done +} + +process_svgs() { + for svg in "$TEMP_DIR"/*.svg; do + [ -f "$svg" ] || continue + filename=$(basename "$svg" .svg) + output_file="$OUTPUT_DIR/$filename.webp" + if ! file_exists_in_output "$output_file"; then + convert_svg_to_webp "$svg" "$output_file" + echo "Converted: $svg -> $output_file" + fi + done +} + +process_webps() { + for webp in "$TEMP_DIR"/*.webp; do + [ -f "$webp" ] || continue + filename=$(basename "$webp" .webp) + output_file="$OUTPUT_DIR/$filename.webp" + if ! file_exists_in_output "$output_file"; then + optimize_webp "$webp" "$output_file" + fi + done +} + +process_images +process_svgs +process_webps + +find "$TEMP_DIR" -type f ! -name '*.jpg' ! -name '*.jpeg' ! -name '*.png' ! -name '*.svg' -exec cp -v {} "$OUTPUT_DIR/" \; + +files_count=$(find "$INPUT_DIR" -type f | wc -l) +echo "$files_count files in $INPUT_DIR" + +total=$(find "$OUTPUT_DIR" -type f | wc -l) +echo "Total: $total files in $OUTPUT_DIR" + +rm -rf "$TEMP_DIR" + +echo "Optimization completed." diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..882855d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests==2.32.3 +unidecode==1.3.8