36 Commits

Author SHA1 Message Date
Jamie Hardt
4a0d19ade1 Added 3.13 to classifiers. 2025-05-25 07:58:55 -07:00
Jamie Hardt
df6c783c51 Added 3.13 to test matrix 2025-05-25 07:57:42 -07:00
Jamie Hardt
f0b232b2b6 autopep 2025-05-25 07:54:50 -07:00
Jamie Hardt
519c6403ba Nudged version 2025-05-25 07:52:11 -07:00
Jamie Hardt
d29c36eafa Fixed some bugs I introduced, fixed entrypoint 2025-05-25 07:50:37 -07:00
Jamie Hardt
2095a1fb75 Nudged version 2025-05-25 07:24:07 -07:00
Jamie Hardt
70defcc46c fixed typo in copyright line 2025-05-25 07:23:25 -07:00
Jamie Hardt
d156b6df89 Added notes 2025-05-25 07:21:50 -07:00
Jamie Hardt
3ba9d7933e Merge branch 'master' of https://github.com/iluvcapra/ptulsconv 2025-05-25 07:16:45 -07:00
Jamie Hardt
b0c40ee0b6 Merged 2025-05-25 07:16:35 -07:00
Jamie Hardt
921b0f07af Update pyproject.toml
Fixing sphinx dependencies
2025-05-25 07:13:11 -07:00
Jamie Hardt
57764bc859 Update conf.py 2025-05-25 07:05:24 -07:00
Jamie Hardt
779c93282c Update conf.py
Updated copyright message
2025-05-25 07:04:17 -07:00
Jamie Hardt
9684be6c7e Update __init__.py 2025-05-25 07:03:28 -07:00
Jamie Hardt
484a70fc8e Update __init__.py 2025-05-25 07:01:47 -07:00
Jamie Hardt
5aa005c317 Update conf.py 2025-05-25 07:00:44 -07:00
Jamie Hardt
454adea3d1 Merge pull request #13 from iluvcapra/maint-poetry
Upgrade build tool to Poetry
2025-05-24 22:25:53 -07:00
Jamie Hardt
1e6546dab5 Tweak file for flake 2025-05-24 22:24:45 -07:00
Jamie Hardt
8b262d3bfb Rearranged pyproject, brought in metadata 2025-05-24 22:22:04 -07:00
Jamie Hardt
630e7960dc Making changes for peotry 2025-05-24 22:20:15 -07:00
Jamie Hardt
aa7b418121 Update __init__.py
Nudging version to 2.2.1
2025-05-24 21:58:50 -07:00
Jamie Hardt
a519a525b2 Update pythonpublish.yml
Updating python publish action to the latest version
2025-05-24 21:54:42 -07:00
Jamie Hardt
1412efe509 autopep 2025-05-18 13:39:06 -07:00
Jamie Hardt
12a6c05467 autopep 2025-05-18 13:37:46 -07:00
Jamie Hardt
cf87986014 autopep'd test 2025-05-18 13:35:12 -07:00
Jamie Hardt
67533879f8 Rewrote parsing to handle old & new-style markers 2025-05-18 13:33:51 -07:00
Jamie Hardt
f847b88aa3 Nudged version and copyright date 2025-05-17 12:06:56 -07:00
Jamie Hardt
c3a600c5d7 Integrated track marker test case and fixed parser 2025-05-17 12:05:27 -07:00
Jamie Hardt
914783a809 Updated documentation 2025-05-17 11:26:07 -07:00
Jamie Hardt
c638c673e8 Adding track marker export case 2025-05-17 11:23:54 -07:00
Jamie Hardt
15fe6667af Fixed up unit test 2025-05-17 11:23:02 -07:00
Jamie Hardt
d4e23b59eb Adding support for track markers
(Always ignore for now)
2025-05-17 11:19:22 -07:00
Jamie Hardt
a602b09551 flake8 2025-05-17 10:47:21 -07:00
Jamie Hardt
448d93d717 Fix for flake 2025-05-17 10:45:40 -07:00
Jamie Hardt
59e7d40d97 Merge branch 'master' of https://github.com/iluvcapra/ptulsconv 2025-05-11 22:19:26 -07:00
Jamie Hardt
eaa5fe824f Fixed parser logic to handle new-style marker tracks 2025-05-11 22:17:42 -07:00
13 changed files with 150 additions and 65 deletions

View File

@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v2.5.0

View File

@@ -26,7 +26,7 @@ jobs:
- name: Build package
run: python -m build
- name: pypi-publish
uses: pypa/gh-action-pypi-publish@v1.8.6
uses: pypa/gh-action-pypi-publish@v1.12.4
# - name: Report to Mastodon
# uses: cbrgm/mastodon-github-action@v1.0.1
# with:

View File

@@ -3,6 +3,7 @@
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import importlib
import sys
import os
@@ -15,9 +16,9 @@ import ptulsconv
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'ptulsconv'
copyright = '2019-2023 Jamie Hardt. All rights reserved'
# author = ptulsconv.__author__
release = ptulsconv.__version__
copyright = '2019-2025 Jamie Hardt. All rights reserved'
version = "Version 2"
release = importlib.metadata.version("ptulsconv")
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

View File

@@ -6,7 +6,12 @@ Usage Form
Invocations of ptulsconv take the following form:
ptulsconv [options] IN_FILE
ptulsconv [options] [IN_FILE]
`IN_FILE` is a Pro Tools text export in UTF-8 encoding. If `IN_FILE` is
missing, `ptulsconv` will attempt to connect to Pro Tools and read cue data
from the selected tracks of the currently-open session.
Flags

View File

@@ -76,7 +76,10 @@ Fields set in markers, and in marker comments, will be applied to all clips
whose finish is *after* that marker. Fields in markers are applied cumulatively
from breakfast to dinner in the session. The latest marker applying to a clip has
precedence, so if one marker comes after the other, but both define a field, the
value in the later marker
value in the later marker.
All markers on all rulers will be scanned for tags. All markers on tracks will
be ignored.
An important note here is that, always, fields set on the clip name have the
highest precedence. If a field is set in a clip name, the same field set on the

View File

@@ -1,9 +1,3 @@
"""
Parse and convert Pro Tools text exports
"""
__version__ = '2.1.1'
__author__ = 'Jamie Hardt'
__license__ = 'MIT'
__copyright__ = "%s %s (c) 2023 %s. All rights reserved." \
% (__name__, __version__, __author__)

View File

@@ -2,7 +2,7 @@ from optparse import OptionParser, OptionGroup
import datetime
import sys
from ptulsconv import __name__, __copyright__
import ptulsconv
from ptulsconv.commands import convert
from ptulsconv.reporting import print_status_style, \
print_banner_style, print_section_header_style, \
@@ -82,7 +82,7 @@ def main():
parser.add_option_group(informational_options)
print_banner_style(__copyright__)
print_banner_style(ptulsconv.__name__)
(options, args) = parser.parse_args(sys.argv)

View File

@@ -19,11 +19,17 @@ class SessionDescriptor:
self.tracks = kwargs['tracks']
self.markers = kwargs['markers']
def markers_timed(self) -> Iterator[Tuple['MarkerDescriptor', Fraction]]:
def markers_timed(self,
only_ruler_markers: bool = True) -> \
Iterator[Tuple['MarkerDescriptor', Fraction]]:
"""
Iterate each marker in the session with its respective time reference.
"""
for marker in self.markers:
if marker.track_marker and only_ruler_markers:
continue
marker_time = Fraction(marker.time_reference,
int(self.header.sample_rate))
# marker_time = self.header.convert_timecode(marker.location)
@@ -182,6 +188,7 @@ class MarkerDescriptor:
units: str
name: str
comments: str
track_marker: bool
def __init__(self, **kwargs):
self.number = kwargs['number']
@@ -190,3 +197,4 @@ class MarkerDescriptor:
self.units = kwargs['units']
self.name = kwargs['name']
self.comments = kwargs['comments']
self.track_marker = kwargs['track_marker']

View File

@@ -9,7 +9,8 @@ from .doc_entity import SessionDescriptor, HeaderDescriptor, TrackDescriptor, \
protools_text_export_grammar = Grammar(
r"""
document = header files_section? clips_section? plugin_listing?
track_listing? markers_listing?
track_listing? markers_block?
header = "SESSION NAME:" fs string_value rs
"SAMPLE RATE:" fs float_value rs
"BIT DEPTH:" fs integer_value "-bit" rs
@@ -74,17 +75,33 @@ protools_text_export_grammar = Grammar(
track_clip_state = ("Muted" / "Unmuted")
markers_listing = markers_listing_header markers_column_header
marker_record*
markers_listing_header = "M A R K E R S L I S T I N G" rs
markers_column_header = "# " fs "LOCATION " fs
"TIME REFERENCE " fs
"UNITS " fs
"NAME " fs
markers_block = markers_block_header
(markers_list / markers_list_simple)
markers_list_simple = markers_column_header_simple marker_record_simple*
markers_list = markers_column_header marker_record*
markers_block_header = "M A R K E R S L I S T I N G" rs
markers_column_header_simple =
"# LOCATION TIME REFERENCE "
"UNITS NAME "
"COMMENTS" rs
markers_column_header =
"# LOCATION TIME REFERENCE "
"UNITS NAME "
"TRACK NAME "
"TRACK TYPE COMMENTS" rs
marker_record_simple = integer_value isp fs string_value fs
integer_value isp fs string_value fs string_value
fs string_value rs
marker_record = integer_value isp fs string_value fs integer_value isp fs
string_value fs string_value fs string_value rs
string_value fs string_value fs string_value fs
string_value fs string_value rs
fs = "\t"
rs = "\n"
@@ -231,22 +248,37 @@ class DocParserVisitor(NodeVisitor):
return node.text
@staticmethod
def visit_markers_listing(_, visited_children):
def visit_markers_block(_, visited_children):
markers = []
for marker in visited_children[2]:
for marker in visited_children[1][0][1]:
markers.append(marker)
return markers
@staticmethod
def visit_marker_record(_, visited_children):
def visit_marker_record_simple(_, visited_children):
return MarkerDescriptor(number=visited_children[0],
location=visited_children[3],
time_reference=visited_children[5],
units=visited_children[8],
name=visited_children[10],
comments=visited_children[12])
comments=visited_children[12],
track_marker=False)
@staticmethod
def visit_marker_record(_, visited_children):
track_type = visited_children[15]
is_track_marker = (track_type == "Track")
return MarkerDescriptor(number=visited_children[0],
location=visited_children[3],
time_reference=visited_children[5],
units=visited_children[8],
name=visited_children[10],
comments=visited_children[16],
track_marker=is_track_marker)
@staticmethod
def visit_formatted_clip_name(_, visited_children):

View File

@@ -1,13 +1,5 @@
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "ptulsconv"
authors = [
{name = "Jamie Hardt", email = "jamiehardt@me.com"},
]
readme = "README.md"
license = { file = "LICENSE" }
classifiers = [
'License :: OSI Approved :: MIT License',
@@ -18,36 +10,43 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Development Status :: 5 - Production/Stable",
"Topic :: Text Processing :: Filters"
]
requires-python = ">=3.8"
dynamic = ["version", "description"]
keywords = ["text-processing", "parsers", "film",
"broadcast", "editing", "editorial"]
dependencies = [
'parsimonious',
'tqdm',
'reportlab',
'py-ptsl >= 101.1.0'
]
[project.optional-dependencies]
doc = [
"Sphinx ~= 5.3.0",
"sphinx-rtd-theme >= 1.1.1"
]
[tool.flit.module]
[tool.poetry]
name = "ptulsconv"
version = "2.2.4"
description = "Read Pro Tools Text exports and generate PDF ADR Reports, JSON"
authors = ["Jamie Hardt <jamiehardt@me.com>"]
license = "MIT"
readme = "README.md"
[project.scripts]
ptulsconv = "ptulsconv.__main__:main"
[tool.poetry.dependencies]
python = "^3.8"
parsimonious = "^0.10.0"
tqdm = "^4.67.1"
reportlab = "^4.4.1"
py-ptsl = "^101.1.0"
sphinx_rtd_theme = {version= '>= 1.1.1', optional=true}
sphinx = {version= '>= 5.3.0', optional=true}
[project.entry_points.console_scripts]
[tool.poetry.extras]
doc = ['sphinx', 'sphinx_rtd_theme']
[tool.poetry.scripts]
ptulsconv = 'ptulsconv.__main__:main'
[project.urls]
Source = 'https://github.com/iluvcapra/ptulsconv'
Issues = 'https://github.com/iluvcapra/ptulsconv/issues'
Documentation = 'https://ptulsconv.readthedocs.io/'
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,24 @@
SESSION NAME: Test for ptulsconv
SAMPLE RATE: 48000.000000
BIT DEPTH: 24-bit
SESSION START TIMECODE: 00:00:00:00
TIMECODE FORMAT: 23.976 Frame
# OF AUDIO TRACKS: 1
# OF AUDIO CLIPS: 0
# OF AUDIO FILES: 0
T R A C K L I S T I N G
TRACK NAME: Hamlet
COMMENTS: {Actor=Laurence Olivier}
USER DELAY: 0 Samples
STATE:
CHANNEL EVENT CLIP NAME START TIME END TIME DURATION STATE
1 1 Test Line 1 $QN=T1001 00:00:00:00 00:00:02:00 00:00:02:00 Unmuted
1 2 Test Line 2 $QN=T1002 00:00:04:00 00:00:06:00 00:00:02:00 Unmuted
M A R K E R S L I S T I N G
# LOCATION TIME REFERENCE UNITS NAME TRACK NAME TRACK TYPE COMMENTS
1 00:00:00:00 0 Samples {Title=Multiple Marker Rulers Project} Markers Ruler
2 00:00:04:00 192192 Samples Track Marker Hamlet Track

View File

@@ -2,33 +2,52 @@ import unittest
import tempfile
import sys
import os.path
import os
import glob
from ptulsconv import commands
class TestPDFExport(unittest.TestCase):
def test_report_generation(self):
"""
Setp through every text file in export_cases and make sure it can
be converted into PDF docs without throwing an error
"""
files = [os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting.txt"]
#files.append(os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting2.txt")
files = []
files = [os.path.dirname(__file__) +
"/../export_cases/Robin Hood Spotting.txt"]
for path in files:
tempdir = tempfile.TemporaryDirectory()
os.chdir(tempdir.name)
try:
commands.convert(input_file=path, major_mode='doc')
except:
assert False, "Error processing file %s" % path
except Exception as e:
print("Error in test_report_generation")
print(f"File: {path}")
print(repr(e))
raise e
finally:
tempdir.cleanup()
def test_report_generation_track_markers(self):
files = []
files.append(os.path.dirname(__file__) +
"/../export_cases/Test for ptulsconv.txt")
for path in files:
tempdir = tempfile.TemporaryDirectory()
os.chdir(tempdir.name)
try:
commands.convert(input_file=path, major_mode='doc')
except Exception as e:
print("Error in test_report_generation_track_markers")
print(f"File: {path}")
print(repr(e))
raise e
finally:
tempdir.cleanup()
if __name__ == '__main__':
unittest.main()

View File

@@ -102,14 +102,14 @@ class TestTagCompiler(unittest.TestCase):
time_reference=48000 * 3600,
units="Samples",
name="Marker 1 {Part=1}",
comments=""
comments="", track_marker=False,
),
doc_entity.MarkerDescriptor(number=2,
location="01:00:01:00",
time_reference=48000 * 3601,
units="Samples",
name="Marker 2 {Part=2}",
comments="[M1]"
comments="[M1]", track_marker=False,
),
]