Repository navigation
Conversation
The helper kept its own copy of the format version until the writer brought tla.FORMAT_VERSION. Part of TimeLineAnnotator/project-management#275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…timelines tilia_core.build gives what a script needs besides importing: - new_script_document: a new document with title "Untitled" and empty notes, and no other field. - set_field: sets a field, or adds it after the others; "media length" is refused, as TiLiA's command line refuses it. - set_media_length: a positive, finite number of seconds; refused while media is attached, and for a change to a known length once timelines have components. - load_media: records a local file (absolute, as the writer makes it relative) or a YouTube link. A WAV's length is read from its header; other media take duration_if_error, or the length set while no media was attached. - wav_length: reads the RIFF header with struct, so 32-bit float and WAVE_FORMAT_EXTENSIBLE files, which the wave module refuses, have a length too. - add_timeline: beat, hierarchy, marker or harmony, after the others, with TiLiA's out-of-the-box heights (marker 30, hierarchy 120, beat 69) when none is given. It refuses while the media length is unknown, a height for harmony, a beat pattern for anything but beat, a pattern that doesn't parse, and a height below 10. - find_timeline: by ordinal, or the first by ordinal with a name. The messages are TiLiA's where TiLiA has one. The YouTube pattern is a copy of TiLiA's until the core's media module has one. Part of TimeLineAnnotator/project-management#275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- load_media takes a file only: a folder is refused as missing media, and a path the system can't look at (a name too long, no permission) is refused the same way instead of raising OSError. os.path.isfile rather than Path.exists, which raises for those before Python 3.12. - wav_length reads the oldest, 14-byte fmt chunk, which holds the rate, the byte rate and the block align. - add_timeline raises TypeError for a beat pattern that isn't text, rather than failing inside the parser. - A beat timeline's show_time_signatures comes from the format's default, which is already true; the line that set it again is gone. - Tests for set_field's lists of texts and its TypeError, and issue references with their names. Part of TimeLineAnnotator/project-management#275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Claude
Adds
tilia_core.build. It holds what a script needs besides importing: a new document, its fields, its media and media length, and empty timelines. Everything happens in memory, and onlytla.writewrites a file.new_script_document()givestla.new_document()with the fieldstitle"Untitled" andnotes"", in that order, and no others.set_field(document, name, value)sets a field, or adds it after the others. The value is kept as NFC text, or a list of NFC texts; anything else raisesTypeError.media length, in any letter case, raises TiLiA'sCLI_METADATA_CANT_SET_MEDIA_LENGTHtext.set_media_length(document, seconds)refuses:MEDIA_METADATA_SET_DATA_FAILEDtext. This includes text,bool, NaN and infinity, which a file can't hold.CHANGE_MEDIA_LENGTH_WITH_MEDIA_LOADED.rawcount too. Setting the same length again is allowed, and so is a first length. "The same" means equal, as the spec says; whether a length within a millisecond counts as the same waits for TimeLineAnnotator/project-management#327 (a media length within a millisecond).load_media(document, path, *, duration_if_error=None)records a YouTube link as given. A local path must be a file (elseMEDIA_NOT_FOUND, also for a folder or a path the system can't look at). It is stored as TiLiA's command line stores it: resolved, absolute, with/. The writer makes it relative to the saved file. The length comes from:.wav(in any case), its header;duration_if_error, checked asset_media_lengthchecks a length;ValueErrorwith<name>: give its length with --duration-if-error, or set it first with metadata set-media-length.The change rule of
set_media_lengthapplies. It returns the length set.wav_length(path)reads the RIFF header withstruct: thedatachunk's size over thefmtchunk's byte rate, or block align × sample rate when the byte rate is 0.fmtchunk too, and skips other chunks and their pad bytes.Nonefor a file that isn't a RIFF WAVE, a header it can't read, a length of 0, or anOSError.wavemodule refuses 32-bit float files on every version, andWAVE_FORMAT_EXTENSIBLEbefore 3.12. This reader reads both.add_timeline(document, kind, name="", *, height=None, beat_pattern=None)addsbeat,hierarchy,markerorharmonyafter the others (ordinal = the largest + 1), with a new id. Itsattrsare the format's defaults, as the reader fills them in, so a document built here reads back from its bytes the same.beat_patternas given,"4"by default.CLI_CREATE_TIMELINE_WITHOUT_DURATION);--beat-patternfor any kind but beat, and--heightfor harmony (CLI_ADD_TIMELINE_ARG_NOT_APPLICABLE);tilia_core.timemap.pattern.parsedoesn't complete (Invalid beat pattern '10[': Unclosed '['.).5 is not a valid height., as TiLiA'sset_datarefuses one (TimeLineAnnotator/project-management#316 (which heights timelines add accepts)).TypeError.find_timeline(document, *, name=None, ordinal=None)finds by ordinal first, as TiLiA's command line finds an import's target, or else the first timeline in ordinal order with that name (compared in NFC). If none matches, it raisesNo timeline found with name='…'orNo timeline found with ordinal=….Two stand-ins, which TimeLineAnnotator/project-management#317 (replace build.py's stand-ins) replaces:
tilia.constants.YOUTUBE_URL_REGEX, until the core's media module has its own (TimeLineAnnotator/project-management#176 (media paths));rules.not_validlands with feat(core): one set of rules for the components the importers create #735.tests/importers/import_docs.pyusestla.FORMAT_VERSIONand drops its own copy of the version.Tests
tests/importers/test_build.py, written first:wave, and by hand 32-bit float with afactchunk, 24-bitWAVE_FORMAT_EXTENSIBLEwith an odd-sized chunk before the data, a 14-bytefmtchunk, a zero byte rate, and a streamed data size;tla.canonical_bytesand read back withtla.loads, the same fields and timelines, with each height in the file.uv run --package tilia-core pytest packages/tilia-core -q: 912 passed, 21 skipped, 8 xfailed. The suite passes on Python 3.10 too.python scripts/check_packages.pypasses. black (22.12.0) and ruff are clean.Guarantees. I neutralised the code behind each one, ran
test_build.py(118 tests), then restored it:media lengthisn't a fieldlower()TypeErrorlength > 0isfinite, keeping> 0boollength != knownknown is not Nonerawcomponents countrawcheckload_mediachecks the change tooload_mediachanges nothingmedia_pathset before the length is foundisfileback toPath.existsnot media_pathduration_if_erroris checked.WAVcountslower()Noneexcept OSErrorfmtchunk givesNonefmtchunk is enoughmin% 2None>= 0attrs = {}len(timelines) + 1nfc()A path the system can't look at raises
OSErrorfromPath.existsonly on Linux and macOS before Python 3.12. On Windows, where I ran these, puttingPath.existsback fails only the folder's test. The long name's test is there for CI's Linux and macOS jobs on 3.10 and 3.11, where it should fail without the fix; I couldn't check that on Windows.Part of TimeLineAnnotator/project-management#275
🤖 Generated with Claude Code