Offline python script to index music #62
Replies: 5 comments 1 reply
-
I actually did have that as an option originally, but got rid of it after messing with it a bunch and changing how it worked... gonna add that back now lmao, gimme a day or two and I will get you a python script + instructions. I am actually super excited to see what fun and interesting bugs having that much music will undoubtedly cause. gonna be great for testing if you don't mind relaying the details back to me. |
Beta Was this translation helpful? Give feedback.
-
Ok, for some reason I thought this would be way harder than it was, got it working in like 20min. I tested it a few times on my 256gb and it looks to be working fine so I think this should fix your issue. Hella fast. Here's how to use it, make a media.py file in the root of the sd card (top level of the file system next to the media directories). you can also make media.txt paste the code in and rename it to media.py. then make sure you have python installed (i am using 3.13.3 but any recent should work), open cmd and go to the SD card, usually just type the drive letter with a : so in my case F: and run
|
Beta Was this translation helpful? Give feedback.
-
Awesome, I will give it a try tomorrow. Current index is working, a little sluggish as expected based on the size.Pretty good for an ME. I shared with my son, a future ME. I’m a EE with embedded and software background but impressed with your coding. ThanksOn Aug 14, 2025, at 9:35 AM, Jstudner ***@***.***> wrote:
Ok, for some reason I thought this would be way harder than it was, got it working in like 20min. I tested it a few times on my 256gb and it looks to be working fine so I think this should fix your issue. Hella fast. Here's how to use it, make a media.py file in the root of the sd card (top level of the file system next to the media directories). you can also make media.txt paste the code in and rename it to media.py. then make sure you have python installed (i am using 3.13.3 but any recent should work), open cmd and go to the SD card, usually just type the drive letter with a : so in my case F: and run python media.py It will readout all of the files as they go by and do each dir one by one. Should only take a few mins if that (my whole thing only took about 3 sec for 200 something gb's) Please do let me know if this does the trick!
`import os
import sys
====== EXTENSIONS ======
MOVIE_EXTS = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".m4v", ".wmv", ".flv", ".mpg", ".mpeg", ".ts", ".3gp"]
BOOK_EXTS = [".pdf", ".epub", ".mobi", ".azw3", ".txt"]
MUSIC_EXTS = [".mp3", ".wav", ".flac"]
MEDIA_EXTS = [".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp", ".tiff",
".mp4", ".webm", ".mov", ".avi", ".mkv", ".flv"]
ROOT_PATH = os.getcwd()
OUTPUT_FILE = os.path.join(ROOT_PATH, "media.json")
def is_valid_extension(fname, exts):
return os.path.splitext(fname)[1].lower() in exts
def get_file_base_name(fname):
return os.path.splitext(fname)[0]
def exists_case_insensitive(folder, filename):
path_lower = filename.lower()
try:
for f in os.listdir(folder):
if f.lower() == path_lower:
return True
except FileNotFoundError:
pass
return False
def write_movies(f):
print("\n[Movies] Scanning...")
f.write(' "movies": [\n')
dir_path = os.path.join(ROOT_PATH, "Movies")
first = True
if os.path.exists(dir_path):
for fname in sorted(os.listdir(dir_path)):
if is_valid_extension(fname, MOVIE_EXTS) and os.path.isfile(os.path.join(dir_path, fname)):
if not first: f.write(",\n")
first = False
base = get_file_base_name(fname)
cover = f"movies/{base}.jpg" if exists_case_insensitive(dir_path, f"{base}.jpg") else "placeholder.jpg"
ext = os.path.splitext(fname)[1]
f.write(f' {{ "name": "{base}", "cover": "{cover}", "file": "Movies/{base}{ext}" }}')
print(f" - {fname}")
f.write("\n ],\n")
def write_shows(f):
print("\n[Shows] Scanning...")
f.write(' "shows": [\n')
dir_path = os.path.join(ROOT_PATH, "Shows")
first_show = True
if os.path.exists(dir_path):
for show in sorted(os.listdir(dir_path)):
show_path = os.path.join(dir_path, show)
if os.path.isdir(show_path):
if not first_show: f.write(",\n")
first_show = False
cover = f"shows/{show}.jpg" if exists_case_insensitive(dir_path, f"{show}.jpg") else "placeholder.jpg"
f.write(f' {{"name": "{show}", "cover": "{cover}", "episodes": [\n')
print(f"Show: {show}")
first_ep = True
for ep in sorted(os.listdir(show_path)):
if is_valid_extension(ep, MOVIE_EXTS) and os.path.isfile(os.path.join(show_path, ep)):
if not first_ep: f.write(",\n")
first_ep = False
ep_base = get_file_base_name(ep)
ext = os.path.splitext(ep)[1]
f.write(f' {{ "name": "{ep_base}", "file": "Shows/{show}/{ep_base}{ext}" }}')
print(f" * {ep}")
f.write("\n ]}")
f.write("\n ],\n")
def write_books(f):
print("\n[Books] Scanning...")
f.write(' "books": [\n')
dir_path = os.path.join(ROOT_PATH, "Books")
first = True
if os.path.exists(dir_path):
for fname in sorted(os.listdir(dir_path)):
if is_valid_extension(fname, BOOK_EXTS) and os.path.isfile(os.path.join(dir_path, fname)):
if not first: f.write(",\n")
first = False
base = get_file_base_name(fname)
cover = f"books/{base}.jpg" if exists_case_insensitive(dir_path, f"{base}.jpg") else "placeholder.jpg"
ext = os.path.splitext(fname)[1]
f.write(f' {{ "name": "{base}", "cover": "{cover}", "file": "Books/{base}{ext}" }}')
print(f" - {fname}")
f.write("\n ],\n")
def write_music(f):
print("\n[Music] Scanning...")
f.write(' "music": [\n')
dir_path = os.path.join(ROOT_PATH, "Music")
first = True
if os.path.exists(dir_path):
for fname in sorted(os.listdir(dir_path)):
if is_valid_extension(fname, MUSIC_EXTS) and os.path.isfile(os.path.join(dir_path, fname)):
if not first: f.write(",\n")
first = False
base = get_file_base_name(fname)
cover = f"music/{base}.jpg" if exists_case_insensitive(dir_path, f"{base}.jpg") else "placeholder.jpg"
ext = os.path.splitext(fname)[1]
f.write(f' {{ "name": "{base}", "cover": "{cover}", "file": "Music/{base}{ext}" }}')
print(f" - {fname}")
f.write("\n ],\n")
def write_playlists(f):
print("\n[Playlists] Scanning...")
f.write(' "playlists": {\n')
dir_path = os.path.join(ROOT_PATH, "Music")
first_pl = True
if os.path.exists(dir_path):
for pl in sorted(os.listdir(dir_path)):
pl_path = os.path.join(dir_path, pl)
if os.path.isdir(pl_path):
if not first_pl: f.write(",\n")
first_pl = False
f.write(f' "{pl}": [\n')
print(f"Playlist: {pl}")
tracks = []
for root, _, files in os.walk(pl_path):
rel_root = os.path.relpath(root, dir_path).replace("\", "/")
for t in files:
if is_valid_extension(t, MUSIC_EXTS):
tracks.append(f"{rel_root}/{t}")
for i, track in enumerate(sorted(tracks)):
tname = os.path.basename(track)
base = get_file_base_name(tname)
cover = f"music/{base}.jpg" if exists_case_insensitive(dir_path, f"{base}.jpg") else "placeholder.jpg"
f.write(f' {{ "name": "{base}", "cover": "{cover}", "file": "Music/{track}" }}')
print(f" * {tname}")
if i < len(tracks) - 1:
f.write(",\n")
f.write("\n ]")
f.write("\n },\n")
def write_gallery(f):
print("\n[Gallery] Scanning...")
f.write(' "gallery": [\n')
dir_path = os.path.join(ROOT_PATH, "Gallery")
first = True
if os.path.exists(dir_path):
for fname in sorted(os.listdir(dir_path)):
if is_valid_extension(fname, MEDIA_EXTS) and os.path.isfile(os.path.join(dir_path, fname)):
if not first: f.write(",\n")
first = False
base = get_file_base_name(fname)
f.write(f' {{ "name": "{base}", "file": "Gallery/{fname}" }}')
print(f" - {fname}")
f.write("\n ],\n")
def write_files(f):
print("\n[Files] Scanning...")
f.write(' "files": [\n')
dir_path = os.path.join(ROOT_PATH, "Files")
first = True
if os.path.exists(dir_path):
for fname in sorted(os.listdir(dir_path)):
if os.path.isfile(os.path.join(dir_path, fname)):
if not first: f.write(",\n")
first = False
f.write(f' {{ "name": "{fname}", "file": "Files/{fname}" }}')
print(f" - {fname}")
f.write("\n ]\n")
def main():
print(f"[MediaGen] Running from root: {ROOT_PATH}")
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
f.write("{\n")
write_movies(f)
write_shows(f)
write_books(f)
write_music(f)
write_playlists(f)
write_gallery(f)
write_files(f)
f.write("}\n")
print(f"\n[MediaGen] media.json created successfully at {OUTPUT_FILE}")
if name == "main":
main()
`
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Ive hacked up a version that splits the media into it's own .json file. Setting the html files to just load its own json file has resulted in slightly faster load times. |
Beta Was this translation helpful? Give feedback.
-
This new version fixes the errors in playlists.json. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
For grins, I downloaded my entire 100G music library to a 512G SD card. I forced it to rebuild the media index file(?) under the settings tab which will take several hours to run. I'm not a python guy, but is it possible to run this offline on a PC to get through the process faster?
Beta Was this translation helpful? Give feedback.
All reactions