15 Commits

Author SHA1 Message Date
Jamie Hardt
88d9aef92a Update __init__.py
Bumped version
2021-10-02 17:34:09 -07:00
Jamie Hardt
e5f94bb506 Reorganized README a little 2021-10-02 17:33:11 -07:00
Jamie Hardt
539cae15b7 Update README.md 2021-10-02 17:26:26 -07:00
Jamie Hardt
ee407e9e62 Update README.md 2021-10-02 17:17:45 -07:00
Jamie Hardt
591d966e64 Merge branch 'master' of https://github.com/iluvcapra/ptulsconv 2021-10-02 17:17:03 -07:00
Jamie Hardt
6f2ec325cf Update README.md 2021-10-02 17:16:57 -07:00
Jamie Hardt
ed2a916673 Update python-package.yml 2021-10-02 17:06:45 -07:00
Jamie Hardt
926072ae3c Merge branch 'master' of https://github.com/iluvcapra/ptulsconv 2021-10-02 17:01:43 -07:00
Jamie Hardt
a06b8c8aaa Delete .travis.yml 2021-10-02 17:01:36 -07:00
Jamie Hardt
7cd86332e8 Update python-package.yml 2021-10-02 17:00:35 -07:00
Jamie Hardt
02a96d7143 Update python-package.yml 2021-10-02 16:56:00 -07:00
Jamie Hardt
9043d28a21 Create python-package.yml 2021-10-02 16:53:19 -07:00
Jamie Hardt
81cdca5452 Added 3.9 to Travis tests 2021-10-02 16:50:09 -07:00
Jamie Hardt
68969e77e2 Hard wrap text 2021-10-02 16:26:56 -07:00
Jamie Hardt
d0da79b31b Create Export Items as Text.py 2021-10-02 15:50:44 -07:00
6 changed files with 183 additions and 60 deletions

40
.github/workflows/python-package.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Lint and Test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 ptulsconv tests --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 ptulsconv tests --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
PYTHONPATH=. pytest

View File

@@ -1,9 +0,0 @@
language: python
python:
- "3.7"
- "3.8
script:
- "python -m unittest discover tests"
install:
- "pip install setuptools"
- "pip install parsimonious tqdm"

120
README.md
View File

@@ -1,56 +1,70 @@
[![Build Status](https://travis-ci.com/iluvcapra/ptulsconv.svg?branch=master)](https://travis-ci.com/iluvcapra/ptulsconv) ![](https://img.shields.io/github/license/iluvcapra/ptulsconv.svg)
![](https://img.shields.io/github/license/iluvcapra/ptulsconv.svg) ![](https://img.shields.io/pypi/pyversions/ptulsconv.svg) [![](https://img.shields.io/pypi/v/ptulsconv.svg)](https://pypi.org/project/ptulsconv/) ![](https://img.shields.io/pypi/wheel/ptulsconv.svg) ![](https://img.shields.io/pypi/pyversions/ptulsconv.svg)
[![](https://img.shields.io/pypi/v/ptulsconv.svg)][pypi]
![](https://img.shields.io/pypi/wheel/ptulsconv.svg)
![Lint and Test](https://github.com/iluvcapra/ptulsconv/actions/workflows/python-package.yml/badge.svg)
[pypi]: https://pypi.org/project/ptulsconv/
![Upload Python Package](https://github.com/iluvcapra/ptulsconv/workflows/Upload%20Python%20Package/badge.svg)
# ptulsconv # ptulsconv
Read Pro Tools text exports and generate JSON, PDF reports.
## Notice! Read Pro Tools text exports and generate PDF reports, JSON output.
At this time there are a lot of changes in the HEAD of this package and you should use the last posted Pypi package.
New features and much better reporting, including native PDF reports, are coming soon!
## Installation
The easiest way to install on your site is to use `pip`:
% pip3 install ptulsconv
This will install the necessary libraries on your host and gives you command-line access to the tool through an
entry-point `ptulsconv`. In a terminal window type `ptulsconv -h` for a list of available options.
## Theory of Operation ## Theory of Operation
[Avid Pro Tools][avp] exports a tab-delimited text file organized in multiple parts with an uneven syntax that usually [Avid Pro Tools][avp] can be used to make spotting notes for ADR recording
can't "drop in" to other tools like Excel or Filemaker. This tool accepts a text export from Pro Tools and produces an sessions by creating spotting regions with descriptive text and exporting the
XML file in the `FMPXMLRESULT` schema which Filemaker Pro can import directly into a new table. session as text. This file can then be dropped into Excel or any CSV-reading
app like Filemaker Pro.
**ptulsconv** accepts a text export from Pro Tools and automatically creates
PDF and CSV documents for use in ADR spotting, recording, editing and
reporting, and supplemental JSON documents can be output for use with other
workflows.
### Reports Generated by ptulsconv by Default
1. "ADR Report" lists every line in an export with most useful fields, sorted
by time.
2. "Continuity" lists every scene sorted by time.
3. "Line Count" lists a count of every line, collated by reel number and by
effort/TV/optional line designation.
4. "CSV" is a folder of files of all lines collated by character and reel
as CSV files, for use by studio cueing workflows.
5. "Director Logs" is a folder of PDFs formatted like the "ADR Report" except
collated by character.
6. "Supervisor Logs" creates a PDF report for every character, with one line
per page, optimized for note-taking.
7. "Talent Scripts" is a minimal PDF layout of just timecode and line prompt,
collated by character.
In the default mode, all of the clips are parsed and converted into a flat list of events, one Filemaker Pro row per
clip with a start and finish time, track name, session name, etc. Timecodes are parsed and converted into frame counts
and seconds. Text is then parsed for descriptive meta-tags and these are assigned to columns in the output list.
[avp]: http://www.avid.com/pro-tools [avp]: http://www.avid.com/pro-tools
### Fields in Clip Names
Track names, track comments, and clip names can also contain meta-tags, or "fields," to add additional columns to the ### Adding Detailed Info to Clip Names with Fields
output. Thus, if a clip has the name:
Track names, track comments, and clip names can also contain meta-tags, or
"fields," to add additional columns to the output. Thus, if a clip has the
name:
`Fireworks explosion {note=Replace for final} $V=1 [FX] [DESIGN]` `Fireworks explosion {note=Replace for final} $V=1 [FX] [DESIGN]`
The row output for this clip will contain columns for the values: The row output for this clip will contain columns for the values:
|...| PT.Clip.Name | note | V | FX | DESIGN | ... | |...| PT.Clip.Name | note | V | FX | DESIGN | ... |
|---|------------|------|---|----|--------|----| |---|--------------------|-------------------|---|----|--------|-----|
|...| Fireworks explosion| Replace for final | 1 | FX | DESIGN | ... | |...| Fireworks explosion| Replace for final | 1 | FX | DESIGN | ... |
These fields can be defined in the clip name in three ways: These fields can be defined in the clip name in three ways:
* `$NAME=VALUE` creates a field named `NAME` with a one-word value `VALUE`. * `$NAME=VALUE` creates a field named `NAME` with a one-word value `VALUE`.
* `{NAME=VALUE}` creates a field named `NAME` with the value `VALUE`. `VALUE` in this case may contain spaces or any * `{NAME=VALUE}` creates a field named `NAME` with the value `VALUE`. `VALUE`
character up to the closing bracket. in this case may contain spaces or any character up to the closing bracket.
* `[NAME]` creates a field named `NAME` with a value `NAME`. This can be used to create a boolean-valued field; in the * `[NAME]` creates a field named `NAME` with a value `NAME`. This can be used
output, clips with the field will have it, and clips without will have the column with an empty value. to create a boolean-valued field; in the output, clips with the field will
have it, and clips without will have the column with an empty value.
For example, if two clips are named: For example, if two clips are named:
@@ -68,30 +82,46 @@ The output will contain the range:
### Fields in Track Names and Markers ### Fields in Track Names and Markers
Fields set in track names, and in track comments, will be applied to each clip on that track. If a track comment Fields set in track names, and in track comments, will be applied to each clip
contains the text `{Dept=Foley}` for example, every clip on that track will have a "Foley" value in a "Dept" column. on that track. If a track comment contains the text `{Dept=Foley}` for
example, every clip on that track will have a "Foley" value in a "Dept" column.
Likewise, fields set on the session name will apply to all clips in the session. Likewise, fields set on the session name will apply to all clips in the session.
Fields set in markers, and in marker comments, will be applied to all clips whose finish is *after* that marker. Fields Fields set in markers, and in marker comments, will be applied to all clips
in markers are applied cumulatively from breakfast to dinner in the session. The latest marker applying to a clip has whose finish is *after* that marker. Fields in markers are applied cumulatively
precedence, so if one marker comes after the other, but both define a field, the value in the later marker 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 prevails.
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 An important note here is that, always, fields set on the clip name have the
name, the same field set on the track, the value set on the clip will prevail. highest precedence. If a field is set in a clip name, the same field set on the
track, the value set on the clip will prevail.
### Using `@` to Apply Fields to a Span of Clips ### Using `@` to Apply Fields to a Span of Clips
A clip name beginning with "@" will not be included in the CSV output, but its fields will be applied to clips within A clip name beginning with "@" will not be included in the CSV output, but its
its time range on lower tracks. fields will be applied to clips within its time range on lower tracks.
If track 1 has a clip named `@ {Sc=1- The House}`, any clips beginning within that range on lower tracks will have a If track 1 has a clip named `@ {Sc=1- The House}`, any clips beginning within
field `Sc` with that value. that range on lower tracks will have a field `Sc` with that value.
### Using `&` to Combine Clips ### Using `&` to Combine Clips
A clip name beginning with "&" will have its parsed clip name appended to the preceding cue, and the fields of following A clip name beginning with "&" will have its parsed clip name appended to the
cues will be applied (later clips having precedence). The clips need not be touching, and the clips will be combined preceding cue, and the fields of following cues will be applied (later clips
into a single row of the output. The start time of the first clip will become the start time of the row, and the finish having precedence). The clips need not be touching, and the clips will be
time of the last clip will become the finish time of the row. combined into a single row of the output. The start time of the first clip
will become the start time of the row, and the finish time of the last clip
will become the finish time of the row.
## Installation
The easiest way to install on your site is to use `pip`:
% pip3 install ptulsconv
This will install the necessary libraries on your host and gives you
command-line access to the tool through an entry-point `ptulsconv`. In a
terminal window type `ptulsconv -h` for a list of available options.

View File

@@ -1,5 +1,5 @@
from ptulsconv.docparser.ptuls_grammar import protools_text_export_grammar from ptulsconv.docparser.ptuls_grammar import protools_text_export_grammar
__version__ = '0.8.0' __version__ = '0.8.1'
__author__ = 'Jamie Hardt' __author__ = 'Jamie Hardt'
__license__ = 'MIT' __license__ = 'MIT'

View File

@@ -0,0 +1,62 @@
# Export Items as Text.py
# (c) 2021 Jamie Hardt. All rights reserved.
#
#
import json
import os.path
import datetime
item_records = list()
for i in range(0, RPR_CountMediaItems(0) ):
this_item = RPR_GetMediaItem(0, i)
item_record = {}
item_record["mute"] = True if RPR_GetMediaItemInfo_Value(this_item, "B_MUTE_ACTUAL") > 0. else False
item_record["duration"] = RPR_GetMediaItemInfo_Value(this_item, "D_LENGTH")
_, item_record["duration_tc"], _, _, _ = RPR_format_timestr_len(item_record["duration"], "", 128, 0., 5)
item_record["position"] = RPR_GetMediaItemInfo_Value(this_item, "D_POSITION")
_, item_record["position_tc"], _, _ = RPR_format_timestr_pos(item_record["position"], "", 128, 5)
item_record["selected"] = True if RPR_GetMediaItemInfo_Value(this_item, "B_UISEL") > 0. else False
_, _, _, item_record["notes"], _ = RPR_GetSetMediaItemInfo_String(this_item, "P_NOTES", "", False)
_, _, _, item_record["item_guid"], _ = RPR_GetSetMediaItemInfo_String(this_item, "GUID", "", False)
active_take = RPR_GetActiveTake(this_item)
_, _, _, item_record["active_take_name"], _ = RPR_GetSetMediaItemTakeInfo_String(active_take, "P_NAME", "", False)
_, _, _, item_record["active_take_guid"], _ = RPR_GetSetMediaItemTakeInfo_String(active_take, "GUID", "", False)
item_track = RPR_GetMediaItemTrack(this_item)
_, _, _, item_record["track_name"], _ = RPR_GetSetMediaTrackInfo_String(item_track, "P_NAME", "", False)
_, _, _, item_record["track_guid"], _ = RPR_GetSetMediaTrackInfo_String(item_track, "GUID", "", False)
item_record["track_index"] = RPR_GetMediaTrackInfo_Value(item_track, "IP_TRACKNUMBER")
item_record["track_muted"] = True if RPR_GetMediaTrackInfo_Value(item_track, "B_MUTE") > 0. else False
item_records = item_records + [item_record]
output = dict()
output["items"] = item_records
_, output["project_title"], _ = RPR_GetProjectName(0, "", 1024)
_, _, output["project_author"], _ = RPR_GetSetProjectAuthor(0, False, "", 1024)
output["project_frame_rate"], _, output["project_drop_frame"] = RPR_TimeMap_curFrameRate(0, True)
output_path, _ = RPR_GetProjectPath("", 1024)
now = datetime.datetime.now()
output_title = output["project_title"]
if output_title == "":
output_title = "unsaved project"
output_file_name = "%s Text Export %s.txt" % (output_title, now.strftime('%Y%m%d_%H%M'))
output_path = output_path + "/" + output_file_name
with open(output_path, "w") as f:
json.dump(output, f, allow_nan=True, indent=4)
RPR_ShowMessageBox("Exported text file \"%s\" to project folder." % output_file_name, "Text Export Complete", 0)
#RPR_ShowConsoleMsg(output_path)

View File

@@ -25,9 +25,9 @@ setup(name='ptulsconv',
'Topic :: Multimedia :: Sound/Audio', 'Topic :: Multimedia :: Sound/Audio',
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.8",
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",
"Topic :: Text Processing :: Filters", "Topic :: Text Processing :: Filters"],
"Topic :: Text Processing :: Markup :: XML"],
packages=['ptulsconv'], packages=['ptulsconv'],
keywords='text-processing parsers film tv editing editorial', keywords='text-processing parsers film tv editing editorial',
install_requires=['parsimonious', 'tqdm', 'reportlab'], install_requires=['parsimonious', 'tqdm', 'reportlab'],