mirror of
https://github.com/iluvcapra/ptulsconv.git
synced 2025-12-31 17:00:46 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a0d19ade1 | ||
|
|
df6c783c51 | ||
|
|
f0b232b2b6 | ||
|
|
519c6403ba | ||
|
|
d29c36eafa | ||
|
|
2095a1fb75 | ||
|
|
70defcc46c | ||
|
|
d156b6df89 | ||
|
|
3ba9d7933e | ||
|
|
b0c40ee0b6 | ||
|
|
921b0f07af | ||
|
|
57764bc859 | ||
|
|
779c93282c | ||
|
|
9684be6c7e | ||
|
|
484a70fc8e | ||
|
|
5aa005c317 | ||
|
|
454adea3d1 | ||
|
|
1e6546dab5 | ||
|
|
8b262d3bfb | ||
|
|
630e7960dc | ||
|
|
aa7b418121 | ||
|
|
a519a525b2 | ||
|
|
1412efe509 | ||
|
|
12a6c05467 | ||
|
|
cf87986014 | ||
|
|
67533879f8 | ||
|
|
f847b88aa3 | ||
|
|
c3a600c5d7 | ||
|
|
914783a809 | ||
|
|
c638c673e8 | ||
|
|
15fe6667af | ||
|
|
d4e23b59eb | ||
|
|
a602b09551 | ||
|
|
448d93d717 | ||
|
|
59e7d40d97 | ||
|
|
eaa5fe824f |
2
.github/workflows/python-package.yml
vendored
2
.github/workflows/python-package.yml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/pythonpublish.yml
vendored
2
.github/workflows/pythonpublish.yml
vendored
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
"COMMENTS" rs
|
||||
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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
24
tests/export_cases/Test for ptulsconv.txt
Normal file
24
tests/export_cases/Test for ptulsconv.txt
Normal 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
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user