### Install serato-tools Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Install the serato-tools package using pip. Optional dependencies like mutagen, pillow, numpy, and librosa may be required for specific features. ```cmd pip install serato-tools ``` -------------------------------- ### List All Available Smart Crates Source: https://context7.com/bvandrc/serato-tools/llms.txt This example demonstrates how to list all Serato smart crate files available on the system using the `SmartCrate.get_crate_files()` class method. ```python from serato_tools.smart_crate import SmartCrate for path in SmartCrate.get_crate_files(): print(path) ``` -------------------------------- ### List All Available Crates Source: https://context7.com/bvandrc/serato-tools/llms.txt This example demonstrates how to list all Serato crate files available on the system using the `Crate.get_crate_files()` class method. ```python from serato_tools.crate import Crate for path in Crate.get_crate_files(): print(path) ``` -------------------------------- ### Programmatic Track Management in a Crate Source: https://context7.com/bvandrc/serato-tools/llms.txt This example illustrates how to add, remove, and manage tracks within a Serato crate file programmatically. It includes removing duplicates and saving changes. ```python from serato_tools.crate import Crate track_paths = crate.get_track_paths() print(f"Track count: {len(track_paths)}") crate.add_track("/Users/DJ/Music/Dubstep/Chozen - I Wanna Dance.mp3") crate.remove_track("/Users/DJ/Music/Dubstep/OldTrack.mp3") crate.remove_duplicates() crate.save_to_file("/Users/DJ/Music/_Serato_/Subcrates/Dubstep_edited.crate") ``` -------------------------------- ### Find Missing Files in a Crate Interactively Source: https://context7.com/bvandrc/serato-tools/llms.txt This example shows how to use the `find_missing()` method on a `Crate` object to locate and re-link missing tracks, prompting the user for new locations. ```python from serato_tools.crate import Crate crate.find_missing() # prompts for new location of each missing track ``` -------------------------------- ### View Smart Crate Details Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Loads and prints the details of a Serato SmartCrate. Note that modification of SmartCrate rules via code is covered in a separate example. ```python from serato_tools.smart_crate import SmartCrate s_crate = Crate('/Users/Username/Music/_Serato_/SmartCrates/Dubstep.scrate') print(s_crate) ``` -------------------------------- ### Get Crate Details and Add Track Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Retrieves and prints details of a Serato crate, including its tracks and internal structure. It also demonstrates how to add a new track to the crate and save it as a new file. ```python from serato_tools.crate import Crate crate = Crate('/Users/Username/Music/_Serato_/Subcrates/Dubstep.crate') print(crate) # OUTPUT: # # Crate containing 81 tracks: # Music/Dubstep/Saka - backitup.mp3 # Music/Dubstep/Mind Splitter - YAPPIN'.mp3 # Music/Dubstep/Flozone - DO IT.mp3 # Music/Dubstep/Evalution - Throw It Back.mp3 # ... crate.print() # OUTPUT: # # [ ('vrsn', 1.0/Serato ScratchLive Crate), # ('osrt', [('brev', b'\x00')]) # ('ovct', [('tvcn', 'key'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'artist'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'song'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'bpm'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'playCount'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'length'), ('tvcw', '0')]) # ('ovct', [('tvcn', 'added'), ('tvcw', '0')]) # ( 'otrk', # [ ( 'ptrk', # 'Music/Dubstep/Flozone - Candy Paint')]) # ( 'otrk', # [ ( 'ptrk', # 'Music/Dubstep/Mind Splitter - LISTEN TO ME')]) # ('otrk', [('ptrk', 'Music/Dubstep/Flozone - DO IT')]) # ... # Example: Add a track to the crate and save it as a new crate crate.add_track('/Users/Username/Music/Dubstep/Chozen - I Wanna Dance.mp3') crate.save_to_file('/Users/Username/Music/Dubstep/New Crate.crate') ``` -------------------------------- ### Hexdump Output of Serato Markers2 Data Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_markers2.md This is a sample hexdump output showing the initial bytes of decoded Serato Markers2 data. It reveals the tag header ('01 01') and the start of marker entries like 'COLOR' and 'BPMLOCK'. ```text 00000000 01 01 43 4f 4c 4f 52 00 00 00 00 04 00 ff ff ff |..COLOR.........| 00000010 42 50 4d 4c 4f 43 4b 00 00 00 00 01 00 00 |BPMLOCK.......| ``` -------------------------------- ### Read and Modify Track Cues with TrackCuesV2 Source: https://context7.com/bvandrc/serato-tools/llms.txt Use `TrackCuesV2` to parse Serato's `Markers2` GEOB tag. Modify entries via callbacks and save changes. This example shows normalizing cue colors and names, setting track color, and snapping cue positions to beats. ```python import dataclasses from mutagen.id3._frames import TIT1 from serato_tools.track_cues_v2 import TrackCuesV2, CUE_COLORS, TRACK_COLORS file = "/Users/DJ/Music/Techno/Artist - Track.mp3" tags = TrackCuesV2(file) # ── Inspect existing entries ────────────────────────────────────────────────── print(tags) # one entry per line print(tags.get_track_color_name()) # e.g. "LIMEGREEN3" print(tags.is_beatgrid_locked()) # True / False # ── Modify hot cues via callback ────────────────────────────────────────────── def normalize_cues(track: TrackCuesV2.TrackCuesInfo) -> TrackCuesV2.TrackCuesInfo | None: new_cues = [] for cue in track.cues: # Normalize near-red colors → pure red color = ( TrackCuesV2.CueColors.RED.value if cue.color in [TrackCuesV2.CueColors.PINKRED.value, TrackCuesV2.CueColors.MAGENTA.value] else cue.color ) # ALL-CAPS cue names new_cues.append(dataclasses.replace(cue, color=color, name=cue.name.strip().upper())) new_track = dataclasses.replace(track, cues=new_cues) return new_track if new_track != track else None tags.modify_entries(normalize_cues, delete_tags_v1=True) tags.save() # ── Set track color ─────────────────────────────────────────────────────────── tags2 = TrackCuesV2(file) tags2.set_track_color(TrackCuesV2.TrackColors.PURPLE, delete_tags_v1=True) tags2.save() # ── Snap cue positions to the nearest beat (tolerance = 1/16 of a beat) ────── # CLI equivalent: serato_snap_cues_v2 "file.mp3" --snap_cues --snap_tolerance 1/16 tags3 = TrackCuesV2(file) tags3.snap_positions_to_beat(tolerance_beats=1/16) tags3.save() # Output: " Snapped by -12 ms" (printed for each moved cue) ``` -------------------------------- ### Modify SmartCrate Rule via Code Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Modifies a specific rule within a Serato SmartCrate programmatically. This example changes the 'grouping' rule to 'UNTAGGED'. ```python from serato_tools.smart_crate import SmartCrate crate = SmartCrate('/Users/Username/Music/_Serato_/SmartCrates/Dubstep.scrate') def modify_rule(rule: SmartCrate.Rule): if rule.field != SmartCrate.RULE_FIELD["grouping"]: return rule rule.set_value(SmartCrate.Fields.RULE_VALUE_TEXT, "UNTAGGED") return rule crate.modify_rules(modify_rule) crate.save() ``` -------------------------------- ### Modify a Smart Crate Rule via the Rule API Source: https://context7.com/bvandrc/serato-tools/llms.txt This example demonstrates how to programmatically update a specific rule within a Serato smart crate, such as modifying the grouping rule's value and comparison type. It iterates through entries and applies changes. ```python from serato_tools.smart_crate import SmartCrate from serato_tools.utils.crate_base import CrateBase def update_grouping_rule(rule: SmartCrate.Rule) -> SmartCrate.Rule: if rule.field != SmartCrate.RuleField.GROUPING: return rule rule.set_value("UNTAGGED") # update the match value rule.set_comparison(SmartCrate.RuleComparison.STR_IS) return rule # Iterate entries manually (Rule objects wrap raw entry lists) for f, v in scrate.entries: if f == CrateBase.Fields.SMARTCRATE_RULE: rule = SmartCrate.Rule(v) update_grouping_rule(rule) ``` -------------------------------- ### CLI Equivalents for Smart Crate Management Source: https://context7.com/bvandrc/serato-tools/llms.txt This section provides command-line interface (CLI) commands that mirror the functionality of the `set_rule` and `delete_rule` methods for managing Serato smart crates. ```bash # serato_smartcrate "Dubstep.scrate" --set_rules --grouping str_is TAGGED # serato_smartcrate --all --set_rules --grouping str_contains NEW --bpm int_is_ge 128 ``` -------------------------------- ### Load and Inspect a Crate File Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet shows how to load a Serato crate file and inspect its contents, including printing track paths in different formats. Requires the `Crate` class. ```python from serato_tools.crate import Crate crate = Crate("/Users/DJ/Music/_Serato_/Subcrates/Dubstep.crate") print(crate) # pretty-prints all binary fields crate.print_track_paths() # one path per line crate.print_track_paths(filenames_only=True) # basenames without extension ``` -------------------------------- ### Inspect Serato Smart Crate Rules Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet shows how to load a Serato smart crate file and inspect its contents, including rules. Requires the `SmartCrate` class. ```python from serato_tools.smart_crate import SmartCrate scrate = SmartCrate("/Users/DJ/Music/_Serato_/SmartCrates/Dubstep.scrate") print(scrate) # prints all binary entries including rules ``` -------------------------------- ### List Available Crates and Smart Crates Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Prints a list of all available Serato crate files and smart crate files on the system. This is useful for discovering existing crates. ```python from serato_tools.crate import Crate print('\n'.join(Crate.get_crate_files())) from serato_tools.smart_crate import SmartCrate print('\n'.join(SmartCrate.get_crate_files())) ``` -------------------------------- ### Snap Cue Positions to Beatgrid Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Snaps cue positions to the nearest beat within a specified tolerance. Use `--snap_cues` to enable snapping and `--snap_tolerance` to define the acceptable deviation from a beat. ```cmd serato_snap_cues_v2 "/Users/Username/Music/Dubstep/Some Track.mp3" --snap_cues --snap_tolerance 1/16 ``` -------------------------------- ### Add All Tracks from a Directory to a Crate Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet demonstrates how to add all tracks from a specified directory into a Serato crate, with an option to replace existing tracks. Requires a loaded `Crate` object. ```python from serato_tools.crate import Crate crate.add_tracks_from_dir("/Users/DJ/Music/Techno", replace=False) crate.save() ``` -------------------------------- ### SeratoBinFile - Crate Operations Source: https://context7.com/bvandrc/serato-tools/llms.txt Provides methods for loading, saving, filtering, and modifying tracks within a Serato crate file. Supports JSON export/import for debugging and bulk path changes. ```python from serato_tools.crate import Crate crate = Crate("/Users/DJ/Music/_Serato_/Subcrates/Dubstep.crate") # ── Export to JSON for debugging ────────────────────────────────────────────── crate.write_json("/tmp/dubstep_crate.json") # ── Load back from JSON ─────────────────────────────────────────────────────── import json with open("/tmp/dubstep_crate.json") as f: data = json.load(f) # crate.from_json_object(data) # round-trip # ── Filter tracks in-place ──────────────────────────────────────────────────── crate.filter_tracks(lambda track: "dubstep" in track.relpath.lower()) crate.save() # ── Generic modify_tracks ───────────────────────────────────────────────────── def uppercase_path(track: Crate.Track) -> Crate.Track: # Just an illustrative example; real use-cases involve path migration return track crate.modify_tracks(uppercase_path) # ── Bulk path change (e.g. after moving music folder) ──────────────────────── crate.change_track_path( src="Music/OldFolder/Artist - Track.mp3", dest="Music/NewFolder/Artist - Track.mp3", ) crate.save() ``` -------------------------------- ### Analyze and Set Dynamic Beatgrid Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Analyzes a track to determine a dynamic beatgrid, suitable for tracks with non-consistent BPM. It's recommended to review the resulting beatgrid in Serato for potential adjustments. ```cmd >>> serato_analyze_beatgrid "Music/Dubstep/Mind Splitter - YAPPIN'.mp3" ``` -------------------------------- ### Render Serato Waveform Overview with TrackWaveform Source: https://context7.com/bvandrc/serato-tools/llms.txt Use TrackWaveform to decode the Serato Overview GEOB tag and render it as a PIL Image. Requires the Pillow library. The draw_image() method returns a 240x16 image. ```python from serato_tools.track_waveform import TrackWaveform file = "/Users/DJ/Music/House/Artist - Club Mix.mp3" tags = TrackWaveform(file) img = tags.draw_image() # requires pillow img.show() # display in default viewer img.save("/tmp/waveform.png") print(f"Image size: {img.size}") # (240, 16) ``` -------------------------------- ### Manage Serato Replay-Gain Tags with TrackGain Source: https://context7.com/bvandrc/serato-tools/llms.txt TrackGain manages Serato-specific replay-gain tags (replaygain_SeratoGain_gain and replaygain_SeratoGain_peak). Use set_and_save() to update values and delete() to remove the tags. ```python from serato_tools.track_gain import TrackGain file = "/Users/DJ/Music/Techno/Artist - Track.flac" tags = TrackGain(file) print(tags) # gain: -6.3 # peak: 0.987 # Update and save tags.set_and_save(gain=-5.5, peak=0.999) # Remove the tags entirely tags.delete() tags.save() ``` -------------------------------- ### CLI Equivalent for Exporting Crates Source: https://context7.com/bvandrc/serato-tools/llms.txt Command-line interface command to export crates matching glob patterns to a USB drive, with an option to specify a root crate name. ```bash # CLI equivalent serato_usb_export --drive E --crates "*house*" "*techno*" --root_crate "Dave USB" ``` -------------------------------- ### Read and Write BPM and Autogain with TrackAutotags Source: https://context7.com/bvandrc/serato-tools/llms.txt Use TrackAutotags to read and write Serato Autotags, including BPM, autogain, and gain-in-dB values. The save() method writes updated tags back to the audio file. ```python from serato_tools.track_autotags import TrackAutotags file = "/Users/DJ/Music/Techno/Artist - Track.mp3" tags = TrackAutotags(file) # ── Read ────────────────────────────────────────────────────────────────────── print(tags) # bpm: 134.0 # autogain: 0.123 # gaindb: -6.456 print(f"BPM: {tags.bpm} autogain: {tags.autogain} gaindb: {tags.gaindb}") # ── Modify and save ─────────────────────────────────────────────────────────── tags.set(bpm=134.0, gaindb=-5.0) tags.save() # writes updated GEOB tag back to the audio file ``` -------------------------------- ### Display Serato BeatGrid Hex Dump Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_beatgrid.md Use hexdump to view the raw byte content of a Serato BeatGrid file. ```bash $ hexdump -C Serato\ BeatGrid.octet-stream 00000000 01 00 00 00 00 01 3e 9c 28 38 42 e6 00 00 37 |......>.(8B...7| 0000000f ``` -------------------------------- ### Parse and Analyze Beat Grids with TrackBeatgrid Source: https://context7.com/bvandrc/serato-tools/llms.txt Use TrackBeatgrid to read, inspect, and analyze existing beat grids from Serato GEOB tags. Requires mutagen for full beat list access. The analyze_and_write() method can compute and save dynamic beat grids using librosa. ```python from serato_tools.track_beatgrid import TrackBeatgrid file = "/Users/DJ/Music/Dubstep/Mind Splitter - YAPPIN'.mp3" tags = TrackBeatgrid(file) # ── Inspect existing grid ───────────────────────────────────────────────────── print(tags) # NonTerminalBeatgridMarkerEnhanced(position_s=0.123, beats_till_next_marker=64, bpm=174.0) # TerminalBeatgridMarker(position_s=22.15, bpm=174.0) # Get full beat list (requires mutagen FileType, not raw bytes) beats = tags.get_beats() print(f"Total beats: {len(beats)}") print(f"First beat: {beats[0].position_s:.3f}s at {beats[0].bpm:.1f} BPM") # Find the nearest beat within 1/8 of a beat tolerance nearest_ms = tags.find_nearest_beat(position_ms=5230, tolerance_beats=1/8) print(f"Nearest beat: {nearest_ms} ms") # ── Dynamic beatgrid analysis + save (CLI: serato_analyze_beatgrid "file.mp3") ─ # tags.analyze_and_write() # requires librosa + numpy; reads TBPM from ID3 tag # ── Beat position of a cue ─────────────────────────────────────────────────── from serato_tools.track_cues_v2 import TrackCuesV2 cue_tags = TrackCuesV2(file) for cue in TrackCuesV2.TrackCuesInfo.from_entries(cue_tags.entries).cues: beat_pos = cue_tags.get_beat_position(cue) print(f"Cue {cue.index} lands on beat {beat_pos:.2f}") ``` -------------------------------- ### Hexdump of Serato Autotags File Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_autotags.md Displays the hexadecimal dump of the Serato Autotags binary file. Useful for understanding the raw byte structure. ```bash $ hexdump -C ../shared/analyzed/Serato\ Autotags.octet-stream 00000000 01 01 31 31 35 2e 30 30 00 2d 33 2e 32 35 37 00 |..115.00.-3.257.| 00000010 30 2e 30 30 30 00 |0.000.| 00000016 ``` -------------------------------- ### Display Serato Markers Data Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_markers_.md Use tail and hexdump to display the raw byte data of the Serato Markers tag, formatted as hexadecimal values. ```bash $ tail -c +7 data/id3/hotcue-positions-00m00s0-03m38s4-01m00s0-00m00s1-00m01s0/Serato\ Markers_.octet-stream | hexdump -v -e '"%08.8_ax " 22/1 "%02x " "\n"' ``` -------------------------------- ### Export Crates to USB Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet shows the import statement for the `copy_crates_to_usb` function and `get_crate_files` utility from the `serato_tools.usb_export` module. ```python from serato_tools.usb_export import copy_crates_to_usb, get_crate_files ``` -------------------------------- ### Parse and Modify Serato Library Database with DatabaseV2 Source: https://context7.com/bvandrc/serato-tools/llms.txt DatabaseV2 allows parsing and modification of the Serato library database V2 file. It supports bulk field modifications, track renames, and filtering missing tracks. The database is loaded from the default location. ```python import time from typing import Any from serato_tools.database_v2 import DatabaseV2 db = DatabaseV2() # loads ~/Music/_Serato_/database V2 # ── Print full database contents ────────────────────────────────────────────── print(db) # ── Rename a track (updates DB + all crate files automatically) ─────────────── db.rename_track_file( src="/Users/DJ/Music/Dubstep/5udo - One - Original Mix.mp3", dest="/Users/DJ/Music/Dubstep/5udo - One.mp3", ) # File is renamed on disk; database V2 and all .crate files updated in one call. ``` -------------------------------- ### Export Serato Database to JSON Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet shows how to export the current Serato database to a JSON file for inspection. It uses the 'db.write_json' method. ```python db.write_json("/tmp/serato_db.json") ``` -------------------------------- ### Display Serato Analysis File Header Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_analysis.md Use hexdump to view the raw bytes of the Serato analysis file header. This is useful for identifying the Serato version. ```bash $ hexdump -C ../shared/analyzed/Serato\ Analysis.octet-stream 00000000 02 01 |..| 00000002 ``` -------------------------------- ### High-level Set and Delete Smart Crate Rules API Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet shows how to use the high-level `set_rule` and `delete_rule` methods to manage rules in a Serato smart crate, including setting rules for grouping and BPM, and deleting a genre rule. Requires a loaded `SmartCrate` object. ```python from serato_tools.smart_crate import SmartCrate scrate.set_rule( field=SmartCrate.RuleField.GROUPING, comparison=SmartCrate.RuleComparison.STR_CONTAINS, value="TAGGED", ) scrate.set_rule( field=SmartCrate.RuleField.BPM, comparison=SmartCrate.RuleComparison.INT_IS_GE, value=128, ) scrate.delete_rule(SmartCrate.RuleField.GENRE) scrate.save() ``` -------------------------------- ### Structured Cue Data with TrackCuesV2.TrackCuesInfo Source: https://context7.com/bvandrc/serato-tools/llms.txt Use `TrackCuesInfo` to build or modify cue data programmatically. This class groups raw entries into typed fields and can be converted back to raw entries for saving. ```python from serato_tools.track_cues_v2 import TrackCuesV2 tags = TrackCuesV2("/Users/DJ/Music/House/Artist - Club Mix.mp3") # Build a TrackCuesInfo object directly from the parsed entries info: TrackCuesV2.TrackCuesInfo = TrackCuesV2.TrackCuesInfo.from_entries(tags.entries) print(info.color) # ColorEntry(field1=b'\x00', color=b'\x99\xff\x99') print(info.bpm_lock) # BpmLockEntry(enabled=False) or None for cue in info.cues: # CueEntry fields: index, position (ms), color (bytes), name (str) print(f" Cue {cue.index}: {cue.position} ms color={cue.color.hex()} name={cue.name!r}") for loop in info.loops: print(f" Loop {loop.index}: {loop.startposition}–{loop.endposition} ms locked={loop.locked}") # Programmatic modification without a callback import dataclasses new_cues = [dataclasses.replace(c, name="DROP") for c in info.cues if c.index == 0] new_info = dataclasses.replace(info, cues=new_cues) tags.entries = new_info.to_entries() tags._dump() tags.save() ``` -------------------------------- ### Modify SmartCrate Rule via Command Line Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Modifies the rules of a Serato SmartCrate using the command line interface. This can be applied to a single crate or all crates. ```cmd >>> serato_smartcrate '/Users/Username/Music/_Serato_/SmartCrates/Dubstep.scrate' --set_rules --grouping UNTAGGED ``` ```cmd >>> serato_smartcrate --all --set_rules --grouping UNTAGGED ``` -------------------------------- ### Export Crates to USB Drive Source: https://context7.com/bvandrc/serato-tools/llms.txt Copies specified crates to a USB drive, handling file-level change detection and nesting crates under a root directory. Progress is printed to the console. ```python crate_files = get_crate_files("*house*") + get_crate_files("*techno*") print(f"Exporting {len(crate_files)} crates") copy_crates_to_usb( crate_files=crate_files, dest_drive_dir="E:\\", # Windows drive letter or mount point dest_tracks_dir="Tracks", # flat folder on the drive root_crate="Dave USB", # optional: nests all crates under this name ) ``` -------------------------------- ### Convert 3-byte Plaintext to 4-byte Serato32 Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_markers_.md Use these bitwise operations to convert a standard 3-byte color value into Serato's 4-byte 'serato32' format. Ensure the input bytes `a`, `b`, and `c` are correctly ordered. ```python # Converting 3-byte plaintext into 4-byte Serato32 value z = c & 0x7F y = ((c >> 7) | (b << 1)) & 0x7F x = ((b >> 6) | (a << 2)) & 0x7F w = (a >> 5) color = (w << 24) | (x << 16) | (y << 8) | z ``` -------------------------------- ### Extract and Decode Serato Markers2 Data Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_markers2.md This command extracts the Serato Markers2 tag content, removes null characters, decodes it from base64, and displays it in hexadecimal format. It's useful for inspecting the raw binary data. ```bash $ grep -Poaz '[\[\w/]*' Serato\ Markers2.octet-stream | tr -d '\0' | base64 -d | hexdump -C ``` -------------------------------- ### Convert 4-byte Serato Color to 3-byte RGB Source: https://github.com/bvandrc/serato-tools/blob/main/docs/serato_markers_.md Use these bitwise operations to convert Serato's 4-byte 'serato32' color format back into a standard 3-byte RGB value. The output bytes `a`, `b`, and `c` represent the red, green, and blue components respectively. ```python # Converting 4-byte Serato color into 3-byte RGB c = (z & 0x7F) | ((y & 0x01) << 7) b = ((y & 0x7F) >> 1) | ((x & 0x03) << 6) a = ((x & 0x7F) >> 2) | ((w & 0x07) << 5) color = (a << 16) | (b << 8) | c ``` -------------------------------- ### TrackCuesV2 - Read and modify hot cues, loops, track color, and BPM lock Source: https://context7.com/bvandrc/serato-tools/llms.txt The TrackCuesV2 class parses the Serato Markers2 GEOB tag. It allows inspection and modification of cues, loops, colors, and BPM lock status. Changes can be applied via a callback pattern and saved to the file. ```APIDOC ## TrackCuesV2 – Read and modify hot cues, loops, track color, and BPM lock `TrackCuesV2` parses the `Serato Markers2` GEOB tag. After loading a file the `entries` list contains typed dataclass objects (`CueEntry`, `LoopEntry`, `ColorEntry`, `BpmLockEntry`, `FlipEntry`). Changes are applied through the `modify_entries` callback pattern and persisted with `save()`. ```python import dataclasses from mutagen.id3._frames import TIT1 from serato_tools.track_cues_v2 import TrackCuesV2, CUE_COLORS, TRACK_COLORS file = "/Users/DJ/Music/Techno/Artist - Track.mp3" tags = TrackCuesV2(file) # ── Inspect existing entries ────────────────────────────────────────────────── print(tags) # one entry per line print(tags.get_track_color_name()) # e.g. "LIMEGREEN3" print(tags.is_beatgrid_locked()) # True / False # ── Modify hot cues via callback ────────────────────────────────────────────── def normalize_cues(track: TrackCuesV2.TrackCuesInfo) -> TrackCuesV2.TrackCuesInfo | None: new_cues = [] for cue in track.cues: # Normalize near-red colors → pure red color = TrackCuesV2.CueColors.RED.value if cue.color in [TrackCuesV2.CueColors.PINKRED.value, TrackCuesV2.CueColors.MAGENTA.value] else cue.color # ALL-CAPS cue names new_cues.append(dataclasses.replace(cue, color=color, name=cue.name.strip().upper())) new_track = dataclasses.replace(track, cues=new_cues) return new_track if new_track != track else None tags.modify_entries(normalize_cues, delete_tags_v1=True) tags.save() # ── Set track color ─────────────────────────────────────────────────────────── tags2 = TrackCuesV2(file) tags2.set_track_color(TrackCuesV2.TrackColors.PURPLE, delete_tags_v1=True) tags2.save() # ── Snap cue positions to the nearest beat (tolerance = 1/16 of a beat) ────── # CLI equivalent: serato_snap_cues_v2 "file.mp3" --snap_cues --snap_tolerance 1/16 tags3 = TrackCuesV2(file) tags3.snap_positions_to_beat(tolerance_beats=1/16) tags3.save() # Output: " Snapped by -12 ms" (printed for each moved cue) ``` ``` -------------------------------- ### Export Crates to USB Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Exports specified crates to a USB drive, optimizing file organization by keeping all files in one folder and copying only changed files. This process replaces existing crates on the flash drive but does not delete existing track files. ```cmd >>> serato_usb_export --drive E --crate_matcher *house* *techno* --root_crate="Dave USB" ``` -------------------------------- ### Rename Track File and Update Database Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Renames a track file and simultaneously updates its path in the Serato database to prevent the file from being missing. It is recommended to back up the database file before performing modifications. ```python from serato_tools.database_v2 import DatabaseV2 db = DatabaseV2() db.rename_track_file(src="5udo - One - Original Mix.mp3", dest="5udo - One.mp3") ``` -------------------------------- ### Set Track Color Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Sets the color of a track in Serato. Ensure `delete_tags_v1` is set to `True` for the change to reflect in Serato, as this parameter is related to older Serato versions. ```python from serato_tools.track_cues_v2 import TrackCuesV2, TRACK_COLORS tags = TrackCuesV2(file) tags.set_track_color('/Users/Username/Music/Dubstep/Raaket - ILL.mp3', TRACK_COLORS["purple"], delete_tags_v1=True # Must delete delete_tags_v1 in order for track color change to appear in Serato (since we never change tags_v1 along with it (TODO)). Not sure what tags_v1 is even for, probably older versions of Serato. Have found no issues with deleting this, but use with caution if running an older version of Serato. ) tags.save() ``` -------------------------------- ### Modify Serato Database File Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Modifies specific fields within the Serato database file, such as 'date added' or 'grouping'. This allows for instant updates in Serato without needing to 'Reload Id3 Tags'. A backup of the database is recommended before proceeding. ```python from serato_tools.database_v2 import DatabaseV2 now = int(time.time()) def modify_uadd(filename: str, prev_val: Any): print(f'Serato library change - Changed "date added" to today: {filename}') return now def modify_tadd(filename: str, prev_val: Any): return str(now) def remove_group(filename: str, prev_val: Any): return " " db = DatabaseV2() # a list of field keys can be found in serato_tools.database_v2 db.modify_file( rules=[ {"field": DatabaseV2.Fields.DATE_ADDED_U, "files": files_set_date, "func": modify_uadd}, {"field": DatabaseV2.Fields.DATE_ADDED_T, "files": files_set_date, "func": modify_tadd}, {"field": DatabaseV2.Fields.GROUPING, "func": remove_group}, # all files ] ) ``` -------------------------------- ### Modify Track Metadata and Hot Cues Source: https://github.com/bvandrc/serato-tools/blob/main/README.md Modifies track metadata, including setting ID3 grouping fields based on track color and normalizing cue colors and names. Cues close to red are set to red, and cue names are converted to uppercase. ```python import dataclasses from mutagen.id3._frames import TIT1 from serato_tools.track_cues_v2 import TrackCuesV2, CUE_COLORS, TRACK_COLORS def track_rule(track: TrackCuesV2.TrackCuesInfo) -> TrackCuesV2.TrackCuesInfo | None: # Set ID3 grouping field from track color if track.color is not None: track_color = track.color.color if track_color == TRACK_COLORS["limegreen3"]: tagfile.tags.setall("TIT1", [TIT1(text="TAGGED")]) elif track_color in [TRACK_COLORS["white"], TRACK_COLORS["grey"], TRACK_COLORS["black"]]: tagfile.tags.setall("TIT1", [TIT1(text="UNTAGGED")]) # Normalize cue colors and names new_cues = [] for c in track.cues: # Make "close to red", red. cue_color = CUE_COLORS["red"] if c.color in [CUE_COLORS["pinkred"], CUE_COLORS["magenta"]] else c.color # Make all cuenames all-caps cue_name = c.name.strip().upper() new_cues.append(dataclasses.replace(c, color=cue_color, name=cue_name)) new_track = dataclasses.replace(track, cues=new_cues) return new_track if new_track != track else None tags = TrackCuesV2(file) tags.modify_entries(track_rule, delete_tags_v1=True) tags.save() ``` -------------------------------- ### Modify Serato Database Fields Source: https://context7.com/bvandrc/serato-tools/llms.txt Modifies specific fields (e.g., GROUPING, PLAYED) for a list of files in the Serato database. Requires importing DatabaseV2 and SeratoBinFile.Fields. ```python from serato_tools.utils.bin_file_base import SeratoBinFile from serato_tools.database_v2 import DatabaseV2 # Available fields (sample): # Fields.TITLE "tsng" Fields.ARTIST "tart" # Fields.ALBUM "talb" Fields.BPM "tbpm" # Fields.KEY "tkey" Fields.GENRE "tgen" # Fields.GROUPING "tgrp" Fields.DATE_ADDED_U "uadd" # Fields.DATE_ADDED_T "tadd" Fields.PLAYED "bply" # Fields.MISSING "bmis" Fields.CORRUPT "bcrt" db = DatabaseV2() # Set the GROUPING field for a specific set of files target_files = [ "/Users/DJ/Music/Techno/Track A.mp3", "/Users/DJ/Music/Techno/Track B.mp3", ] db.modify([ { "field": DatabaseV2.Fields.GROUPING, "files": target_files, "func": lambda filename, prev: "TAGGED", }, { "field": DatabaseV2.Fields.PLAYED, "func": lambda filename, prev: False, # mark all tracks unplayed }, ]) db.save() ``` -------------------------------- ### Modify Serato Database Fields Source: https://context7.com/bvandrc/serato-tools/llms.txt This snippet demonstrates how to modify specific fields in the Serato database, such as date added and grouping. It requires the 'DatabaseV2' and 'time' modules. ```python now = int(time.time()) files_to_update = ["/Users/DJ/Music/Dubstep/Artist - Track.mp3"] def set_date_added(filename: str, prev_val: Any): print(f"Resetting date added: {filename}") return now def set_date_added_t(filename: str, prev_val: Any): return str(now) def clear_grouping(filename: str, prev_val: Any): return " " db.modify([ {"field": DatabaseV2.Fields.DATE_ADDED_U, "files": files_to_update, "func": set_date_added}, {"field": DatabaseV2.Fields.DATE_ADDED_T, "files": files_to_update, "func": set_date_added_t}, {"field": DatabaseV2.Fields.GROUPING, "func": clear_grouping}, # applies to all tracks ]) db.save() ``` -------------------------------- ### TrackCuesV2.TrackCuesInfo – Structured view of a track's cue data Source: https://context7.com/bvandrc/serato-tools/llms.txt TrackCuesInfo is a dataclass representing a track's cue data, used in modify_entries callbacks. It groups raw entries into typed fields and can be reconstructed back into raw entries. ```APIDOC ## TrackCuesV2.TrackCuesInfo – Structured view of a track's cue data `TrackCuesInfo` is the dataclass passed to every `modify_entries` callback. It groups the raw `entries` list into typed fields and is reconstructed back into raw entries via `to_entries()`. ```python from serato_tools.track_cues_v2 import TrackCuesV2 tags = TrackCuesV2("/Users/DJ/Music/House/Artist - Club Mix.mp3") # Build a TrackCuesInfo object directly from the parsed entries info: TrackCuesV2.TrackCuesInfo = TrackCuesV2.TrackCuesInfo.from_entries(tags.entries) print(info.color) # ColorEntry(field1=b'\x00', color=b'\x99\xff\x99') print(info.bpm_lock) # BpmLockEntry(enabled=False) or None for cue in info.cues: # CueEntry fields: index, position (ms), color (bytes), name (str) print(f" Cue {cue.index}: {cue.position} ms color={cue.color.hex()} name={cue.name!r}") for loop in info.loops: print(f" Loop {loop.index}: {loop.startposition}–{loop.endposition} ms locked={loop.locked}") # Programmatic modification without a callback import dataclasses new_cues = [dataclasses.replace(c, name="DROP") for c in info.cues if c.index == 0] new_info = dataclasses.replace(info, cues=new_cues) tags.entries = new_info.to_entries() tags._dump() tags.save() ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.