From d71ffb714f22d3c7ef44a1f363b0a68dfc691a83 Mon Sep 17 00:00:00 2001 From: teitoku Date: Wed, 16 Jul 2025 16:01:42 +0900 Subject: [PATCH] Yikes --- .gitignore | 3 ++ README.md | 8 ++++ minecraft.csv | 1 + mood | 72 ++++++++++++++++++++++++++++++ music/.keep | 0 music_db/terraria.csv | 58 ++++++++++++++++++++++++ scripts/data.py | 28 ++++++++++++ scripts/extract_minecraft_music.py | 49 ++++++++++++++++++++ scripts/music_import.py | 71 +++++++++++++++++++++++++++++ 9 files changed, 290 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 minecraft.csv create mode 100755 mood create mode 100644 music/.keep create mode 100644 music_db/terraria.csv create mode 100644 scripts/data.py create mode 100644 scripts/extract_minecraft_music.py create mode 100644 scripts/music_import.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7789082 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +tmp/ +music/* +!music/.keep diff --git a/README.md b/README.md new file mode 100644 index 0000000..d57148b --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# How does it work? + +Basically, I forgot, I know that you have to download music somehow, create +some rules in csv format, just check `music_db/terraria.csv` and use it as +template, then run `scripts/music_import.py` to copy the music in the +`music` directory + +After this you can run the command `. ./mood` to play music diff --git a/minecraft.csv b/minecraft.csv new file mode 100644 index 0000000..50203bd --- /dev/null +++ b/minecraft.csv @@ -0,0 +1 @@ +game/sweden.ogg 6x_sweden.ogg diff --git a/mood b/mood new file mode 100755 index 0000000..df58c2b --- /dev/null +++ b/mood @@ -0,0 +1,72 @@ +#!/bin/sh + +MUSIC_PATH="music" + +urlencode() { + echo $1 \ + | sed 's#/#\%2F#g' \ + | sed 's# #\%20#g' #\ + #| tr -d '"' +} + +if [[ -z $MOOD_ipinfo ]]; then + export MOOD_ipinfo=$(curl ipinfo.io/json 2>/dev/null) +fi + +jqurl() { + echo $(urlencode $(echo $MOOD_ipinfo | jq -r $1)) +} + +gethour() { + echo $RESP \ + | jq -r $1 \ + | cut -dT -f2 +} + +location=$(jqurl '.loc') +timezone=$(jqurl '.timezone') + +URL="https://api.open-meteo.com/v1/forecast?current=weather_code&forecast_days=1&daily=sunrise,sunset" +URL="$URL&timezone=$timezone" +URL="$URL&latitude=$(echo $location | cut -d, -f1)" +URL="$URL&longitude=$(echo $location | cut -d, -f2)" + +RESP=$(curl $URL 2>/dev/null) + +CODE=$(echo $RESP | jq -r '.current.weather_code') +TIME="$(gethour '.current.time')" +SUNRISE="$(gethour '.daily.sunrise[0]')" +SUNSET="$(gethour '.daily.sunset[0]')" +if [[ ( $TIME > $SUNRISE ) && ( $TIME < $SUNSET ) ]]; then + TIME='day' +else + TIME='night' +fi + +echo "Obtained weather code: $CODE" + +T="" +[ $CODE -ge 0 ] && T=$TIME +[ $CODE -ge 40 ] && T='fog' +[ $CODE -ge 50 ] && T='rain' +[ $CODE -ge 70 ] && T='snow' +[ $CODE -ge 80 ] && T='rain' +[ $CODE -ge 85 ] && T='snow' +[ $CODE -ge 90 ] && T='storm' +CODE=$T + +echo "Playing playlist for: $CODE" +echo "" + +FILES=$(find $MUSIC_PATH -regex "$MUSIC_PATH/${CODE}_.*" \ + | sort -R) + +setopt shwordsplit +for line in $FILES; do echo "${line%.*}" | sed "s#^${MUSIC_PATH}/${CODE}_##"; done +unsetopt shwordsplit + +killall mpv &>/dev/null 2>/dev/null + +$(echo $FILES | mpv --playlist=- /dev/null 2>/dev/null &) + +# disown diff --git a/music/.keep b/music/.keep new file mode 100644 index 0000000..e69de29 diff --git a/music_db/terraria.csv b/music_db/terraria.csv new file mode 100644 index 0000000..e9ebf16 --- /dev/null +++ b/music_db/terraria.csv @@ -0,0 +1,58 @@ +day_journey_end.webm "1.4.1 Journey's End (End Credits Theme) Full Original High Quality Soundtrack [l69Txf0jPgU].webm" +day_underground_hallow.webm "12 - Underground Hallow [elJPMUnPFUI].webm" +day_alternate_day.webm "Alternate Day [vB7lYs4z7kE].webm" +night_alternate_underground.webm "Alternate Underground [l7d77DYkpsw].webm" +storm_boss_1.webm "Boss 1 [jp_rl-1rYpQ].webm" +storm_boss_2.webm "Boss 2 [8E8YdqLG5c8].webm" +storm_boss_3.webm "Boss 3 [XdLq3b6uZj8].webm" +night_corruption.webm "Corruption [HkZ-Z0u5eGc].webm" +night_crimson.webm "Crimson [p1QY1CAFiK0].webm" +day_day.webm "Day [x23I8f9PwlI].webm" +type_.webm "Deerclops Boss Theme OST Terraria x Don't Starve Together | An Eye for an Eye Update [47lkXk79K1g].webm" +day_desert.webm "Desert [sELjOl9gP-k].webm" +storm_duke_fishron.webm "Duke Fishron Theme | Terraria 1.4 Journey's End Soundtrack [Mg4ekEx4vho].webm" +night_dungeon.webm "Dungeon [cxRovfKFoI4].webm" +night_eclipse.webm "Eclipse [pMNUlKUMw0E].webm" +night_eerie.webm "Eerie [R2Hs-v5XEFQ].webm" +storm_empress_of_light.webm "Empress of Light Theme Original Soundtrack High Quality Journey's End OST [mP3RAMSgrnI].webm" +snow_frost_moon.webm "Frost Moon [32mi7fttwnQ].webm" +night_goblin_army.webm "Goblin Army [azRSVHjhbXU].webm" +type_.webm "Golem [ifzNfr6DAFk].webm" +night_grave_yard.webm "Graveyard [xy59jRi55o4].webm" +snow_hallow.webm "Hallow [IOEjEbjAR3c].webm" +snow_ice.webm "Ice [WvrciA9TTTw].webm" +day_journey_beginning.webm "Journey's Beginning (Title Screen) [X2frO5mx5C8].webm" +day_space_day.webm "Journey's End OST: Space Day (Console Space) [SCdSLlnKOw0].webm" +rain_jungle.webm "Jungle [ehMCqtBBUXU].webm" +type_.webm "Lihzahrd [_LxrYpJH-v0].webm" +storm_lunar_tower.webm "Lunar Towers [I4bHZF6bOdY].webm" +storm_martian_madness.webm "Martian Madness [2xpOGAkYR_s].webm" +night_moon)lord.webm "Moon Lord [2o0_30JaUhY].webm" +rain_morning_rain.webm "Morning Rain (Console Tutorial) [CFr5rYfzgaI].webm" +night_mushrooms.webm "Mushrooms [7wp1xknPA5A].webm" +night_night.webm "Night [5Amwk16RgEo].webm" +day_ocean.webm "Ocean [fdi06Y6oFDo].webm" +night_ocean_night.webm "Ocean Night (Console Ocean) [hQWyBbDx2oY].webm" +snow_aether.webm "OST - 'Aether' [3F-bKs9ox_A].webm" +type_.webm "Pirate Invasion [E2neOO8N8G8].webm" +storm_plantera.webm "Plantera [g9Nk_TPIB-w].webm" +storm_pumpkin_moon.webm "Pumpkin Moon [lOyhMudpA48].webm" +storm_queen_bee.webm "Queen Bee [Mm1cUubLqaA].webm" +day_queen_slime.webm "Queen Slime [bC4xn3Vh9gk].webm" +rain_rain.webm "Rain [0dmzWlm4_V0].webm" +day_sandstorm.webm "Sandstorm [4FfrhUgvgDw].webm" +rain_slime_rain.webm "Slime Rain [CHSY3tl9Gs4].webm" +night_space.webm "Space [EroCygxKHwk].webm" +rain_surface_jungle.webm "Surface Jungle Night [tf1D5wIemmY].webm" +storm_thunderstorm.webm "Thunderstorm [2cNbAmSTvT0].webm" +day_title_screen.webm "Title Screen [LFmnZ6VMd_4].webm" +day_town_day.webm "Town Day Theme | Terraria 1.4 Journey's End Soundtrack [h8Q0CyunBHo].webm" +night_town_night.webm "Town Night Spoiler [wTKF3JWPS_E].webm" +night_underground.webm "Underground [c-OttnZEXZo].webm" +night_underground_corruption.webm "Underground Corruption [cZEpGtePF4M].webm" +night_undergroun_crimson.webm "Underground Crimson [1MPrk78diZo].webm" +day_underground_desert.webm "Underground Desert [07RSUhz6EVo].webm" +snow_underground_ice.webm "Underground Ice [cYPgRwuAO4I].webm" +rain_undergeound_jungle.webm "Underground Jungle [xIqix-XEp0A].webm" +night_underworld.webm "Underworld [d5tEk9puWH4].webm" +day_windy_day.webm "Windy Day Spoiler [Ecqe_U_IDCo].webm" diff --git a/scripts/data.py b/scripts/data.py new file mode 100644 index 0000000..c5b516d --- /dev/null +++ b/scripts/data.py @@ -0,0 +1,28 @@ +ENV = { + 'usage': [ + 'music_import.py', + '', + '', + '[destination_directory]' + ], + 'help': [ + "Provide a translation, a source and a destination path to copy the files renaming them accordingly, ", + "The translation file is a csv, containing the following entries:", + "" + "" "" + "", + "Using relative path for source and destination file", + "Destination file name should looke something like:", + "", + "_.", + "", + "CODE: weather condition name", + "description: just a way for you to recognize the file and for the system's FS to not overwrite files", + "extension: any format supported by mpv should be ok", + "", + "CODE recognized values are:", "'day' 'night' 'fog' 'rain' 'snow' 'thunder'", + "Only when teh weather is clear (day/night): a check on current time is performed against the known", + "sunset/sunrise time to determine which to pick" + ], + 'dst_dir': './music' +} diff --git a/scripts/extract_minecraft_music.py b/scripts/extract_minecraft_music.py new file mode 100644 index 0000000..02f48ae --- /dev/null +++ b/scripts/extract_minecraft_music.py @@ -0,0 +1,49 @@ +import json, os, platform, shutil, sys + +''' + Copies audio files from indescript hashed folders to named sorted folders. + You may need to change output path. +''' + +MC_ASSETS = '' +# This section should work on any system as well +# print("Your OS is " + platform.system()) +if platform.system() == "Windows": + MC_ASSETS = os.path.expandvars(r"%APPDATA%/.minecraft/assets") +elif platform.system() == "Darwin": + MC_ASSETS = os.path.expanduser(r"~/Library/Application Support/minecraft/assets") +else: + MC_ASSETS = os.path.expanduser(r"~/.minecraft/assets") + + +# Find the latest installed version of minecraft (choose the last element in assets/indexes) +MC_VERSION = os.listdir(MC_ASSETS+"/indexes/")[-1] +# print("Your latest installed version of minecraft is " + MC_VERSION[:-5]) + +# Change this if you want to put the sound files somewhere else +OUTPUT_PATH = os.path.normpath(os.path.expandvars(os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else f"./tmp"))) + +# These are unlikely to change +MC_OBJECT_INDEX = f"{MC_ASSETS}/indexes/{MC_VERSION}" +MC_OBJECTS_PATH = f"{MC_ASSETS}/objects" +MC_SOUNDS = r"minecraft/sounds/" + + +with open(MC_OBJECT_INDEX, "r") as read_file: + # Parse the JSON file into a dictionary + data = json.load(read_file) + + # Find each line with MC_SOUNDS prefix, remove the prefix and keep the rest of the path and the hash + sounds = {k[len(MC_SOUNDS):] : v["hash"] for (k, v) in data["objects"].items() if k.startswith(MC_SOUNDS)} + + for fpath, fhash in sounds.items(): + if fpath.startswith('music'): + # Ensure the paths are good to go for Windows with properly escaped backslashes in the string + src_fpath = os.path.normpath(f"{MC_OBJECTS_PATH}/{fhash[:2]}/{fhash}") + dest_fpath = os.path.normpath(f"{OUTPUT_PATH}/sounds/{fpath}") + + # Make any directories needed to put the output file into as Python expects + os.makedirs(os.path.dirname(dest_fpath), exist_ok=True) + + # Copy the file + shutil.copyfile(src_fpath, dest_fpath) diff --git a/scripts/music_import.py b/scripts/music_import.py new file mode 100644 index 0000000..77724e7 --- /dev/null +++ b/scripts/music_import.py @@ -0,0 +1,71 @@ +import sys +import os + +from data import ENV + +def eprint(*args): + print(*args, file=sys.stderr) + +def solve_or_escape(param): + if not param[0] == '$': + return param + if x[1] == '$': + return param[1:] + return ENV[param[1:]] + +def l_map(x,y): return list(map(x,y)) + +def cp_file(command): + dst = os.path.normpath(f"{ENV['dst']}/{command[0]}") + src = os.path.normpath(f"{ENV['src']}/{command[1]}") + eprint(f'Copying ... "{src}" to "{dst}"') + shutil.copy(src, dst) + +import shutil +def file_import(commands): + try: + l_map(cp_file, commands) + except FileNotFoundError as e: + eprint('Error:', e) + +def main(): + + if "-h" in sys.argv or "--help" in sys.argv: + eprint(); eprint(' ', sys.argv[0]) + eprint(); eprint(' -', ' '.join(ENV['usage'])) + eprint(); [eprint(' ', x) for x in ENV['help']] + eprint() + exit(0) + + if len(sys.argv) < len(ENV['usage']): + eprint('Usage:', ' '.join(ENV['usage'])) + exit(1) + + if len(sys.argv) == len(ENV['usage']): + ENV['dst'] = os.path.normpath(sys.argv[-1]) + + ENV['src'] = os.path.normpath(sys.argv[-2]) + ENV['mus_db'] = os.path.normpath(sys.argv[-3]) + + dst_dir = ENV['dst'] + src_dir = ENV['src'] + mus_db = ENV['mus_db'] + + if not os.path.isfile(mus_db): + eprint(f"{mus_db}: Not a file") + if not os.path.isdir(src_dir): + eprint(f"{src_dir}: Not a directory") + if not os.path.isdir(dst_dir): + eprint(f"{dst_dir}: Not a directory") + + import csv + + config = [] + + with open(mus_db, newline='') as csvfile: + config = [row for row in csv.reader(csvfile, delimiter=' ')] + + file_import(config) + +if __name__ == "__main__": + main()