mirror of
https://github.com/iluvcapra/ptulsconv.git
synced 2026-10-02 01:37:17 +00:00
Compare commits
7 Commits
v4.0.2
..
ab19793bd1
| Author | SHA1 | Date | |
|---|---|---|---|
| ab19793bd1 | |||
| 7730f6be23 | |||
| e286132101 | |||
| 4afe4b7a3e | |||
| cb8de2d785 | |||
| 9e9ad75f77 | |||
| f7808e2236 |
@@ -16,7 +16,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.5.0
|
- uses: actions/checkout@v2.5.0
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
name: Test Toot
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
print-tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Report to Mastodon
|
||||||
|
uses: cbrgm/mastodon-github-action@v1.0.1
|
||||||
|
env:
|
||||||
|
MASTODON_URL: ${{ secrets.MASTODON_URL }}
|
||||||
|
MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }}
|
||||||
|
with:
|
||||||
|
message: |
|
||||||
|
This is a test toot, automatically posted by a github action.
|
||||||
|
|
||||||
|
${{ github.server_url }}/${{ github.repository }}
|
||||||
|
|
||||||
|
${{ github.ref }}
|
||||||
@@ -14,6 +14,9 @@ build:
|
|||||||
pre_install:
|
pre_install:
|
||||||
- pip install --upgrade pip
|
- pip install --upgrade pip
|
||||||
- pip install --upgrade --upgrade-strategy only-if-needed --group doc .
|
- pip install --upgrade --upgrade-strategy only-if-needed --group doc .
|
||||||
|
# build:
|
||||||
|
# html:
|
||||||
|
# - python -m sphinx -T -b html -d _build/doctrees -D language=en . $READTHEDOCS_OUTPUT/html
|
||||||
post_build:
|
post_build:
|
||||||
- echo "Command run at 'post_build' step"
|
- echo "Command run at 'post_build' step"
|
||||||
- echo `date`
|
- echo `date`
|
||||||
@@ -26,3 +29,16 @@ sphinx:
|
|||||||
#If using Sphinx, optionally build your docs in additional formats such as PDF
|
#If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||||
formats:
|
formats:
|
||||||
- pdf
|
- pdf
|
||||||
|
|
||||||
|
# FIXME: We should be installing the `doc` dependency group and not the `doc`
|
||||||
|
# extra.
|
||||||
|
|
||||||
|
#Optionally declare the Python requirements required to build your docs
|
||||||
|
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- method: pip
|
||||||
|
path: .
|
||||||
|
extra_requirements:
|
||||||
|
- doc
|
||||||
|
|
||||||
|
|||||||
+2
-9
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ptulsconv"
|
name = "ptulsconv"
|
||||||
version = "4.0.2"
|
version = "4.0.0"
|
||||||
description = "Read Pro Tools Text exports and generate PDF ADR Reports, JSON"
|
description = "Read Pro Tools Text exports and generate PDF ADR Reports, JSON"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
@@ -9,6 +9,7 @@ license-files = ["LICENSE"]
|
|||||||
keywords = ["text-processing", "parsers", "film",
|
keywords = ["text-processing", "parsers", "film",
|
||||||
"broadcast", "editing", "editorial"]
|
"broadcast", "editing", "editorial"]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
'Topic :: Multimedia',
|
'Topic :: Multimedia',
|
||||||
'Topic :: Multimedia :: Sound/Audio',
|
'Topic :: Multimedia :: Sound/Audio',
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
@@ -16,7 +17,6 @@ classifiers = [
|
|||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
"Programming Language :: Python :: 3.14",
|
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Topic :: Text Processing :: Filters"
|
"Topic :: Text Processing :: Filters"
|
||||||
]
|
]
|
||||||
@@ -42,13 +42,6 @@ doc = [
|
|||||||
"sphinx-rtd-theme>=3.0.2",
|
"sphinx-rtd-theme>=3.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
ignore = [
|
|
||||||
"DTZ005" # datetime created without a tz
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.ruff.lint.per-file-ignores]
|
|
||||||
"reaper/Export Items as Text.py" = ["F821"]
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
ptulsconv = "ptulsconv:__main__.main"
|
ptulsconv = "ptulsconv:__main__.main"
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
# type: ignore[reportUndefinedVariable]
|
|
||||||
|
|
||||||
# Export Items as Text.py
|
# Export Items as Text.py
|
||||||
# (c) 2021 Jamie Hardt. All rights reserved.
|
# (c) 2021 Jamie Hardt. All rights reserved.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
from zoneinfo import ZoneInfo
|
|
||||||
|
|
||||||
item_records = []
|
item_records = list()
|
||||||
|
|
||||||
for i in range(RPR_CountMediaItems(0)):
|
for i in range(RPR_CountMediaItems(0)):
|
||||||
this_item = RPR_GetMediaItem(0, i)
|
this_item = RPR_GetMediaItem(0, i)
|
||||||
|
|
||||||
item_record = {}
|
item_record = {}
|
||||||
item_record["mute"] = RPR_GetMediaItemInfo_Value(this_item, "B_MUTE_ACTUAL") > 0.0
|
item_record["mute"] = (
|
||||||
|
True if RPR_GetMediaItemInfo_Value(this_item, "B_MUTE_ACTUAL") > 0.0 else False
|
||||||
|
)
|
||||||
|
|
||||||
item_record["duration"] = RPR_GetMediaItemInfo_Value(this_item, "D_LENGTH")
|
item_record["duration"] = RPR_GetMediaItemInfo_Value(this_item, "D_LENGTH")
|
||||||
_, item_record["duration_tc"], _, _, _ = RPR_format_timestr_len(
|
_, item_record["duration_tc"], _, _, _ = RPR_format_timestr_len(
|
||||||
@@ -26,7 +26,9 @@ for i in range(RPR_CountMediaItems(0)):
|
|||||||
item_record["position"], "", 128, 5
|
item_record["position"], "", 128, 5
|
||||||
)
|
)
|
||||||
|
|
||||||
item_record["selected"] = RPR_GetMediaItemInfo_Value(this_item, "B_UISEL") > 0.0
|
item_record["selected"] = (
|
||||||
|
True if RPR_GetMediaItemInfo_Value(this_item, "B_UISEL") > 0.0 else False
|
||||||
|
)
|
||||||
_, _, _, item_record["notes"], _ = RPR_GetSetMediaItemInfo_String(
|
_, _, _, item_record["notes"], _ = RPR_GetSetMediaItemInfo_String(
|
||||||
this_item, "P_NOTES", "", False
|
this_item, "P_NOTES", "", False
|
||||||
)
|
)
|
||||||
@@ -52,11 +54,13 @@ for i in range(RPR_CountMediaItems(0)):
|
|||||||
item_record["track_index"] = RPR_GetMediaTrackInfo_Value(
|
item_record["track_index"] = RPR_GetMediaTrackInfo_Value(
|
||||||
item_track, "IP_TRACKNUMBER"
|
item_track, "IP_TRACKNUMBER"
|
||||||
)
|
)
|
||||||
item_record["track_muted"] = RPR_GetMediaTrackInfo_Value(item_track, "B_MUTE") > 0.0
|
item_record["track_muted"] = (
|
||||||
|
True if RPR_GetMediaTrackInfo_Value(item_track, "B_MUTE") > 0.0 else False
|
||||||
|
)
|
||||||
|
|
||||||
item_records = item_records + [item_record]
|
item_records = item_records + [item_record]
|
||||||
|
|
||||||
output = {}
|
output = dict()
|
||||||
output["items"] = item_records
|
output["items"] = item_records
|
||||||
_, output["project_title"], _ = RPR_GetProjectName(0, "", 1024)
|
_, output["project_title"], _ = RPR_GetProjectName(0, "", 1024)
|
||||||
_, _, output["project_author"], _ = RPR_GetSetProjectAuthor(0, False, "", 1024)
|
_, _, output["project_author"], _ = RPR_GetSetProjectAuthor(0, False, "", 1024)
|
||||||
@@ -72,14 +76,15 @@ output_title = output["project_title"]
|
|||||||
if output_title == "":
|
if output_title == "":
|
||||||
output_title = "unsaved project"
|
output_title = "unsaved project"
|
||||||
|
|
||||||
output_file_name = f"{output_title} Text Export {now.strftime('%Y%m%d_%H%M')}.txt"
|
output_file_name = "%s Text Export %s.txt" % (output_title, now.strftime("%Y%m%d_%H%M"))
|
||||||
output_path = output_path + "/" + output_file_name
|
output_path = output_path + "/" + output_file_name
|
||||||
|
|
||||||
with open(output_path, "w") as f:
|
with open(output_path, "w") as f:
|
||||||
json.dump(output, f, allow_nan=True, indent=4)
|
json.dump(output, f, allow_nan=True, indent=4)
|
||||||
|
|
||||||
RPR_ShowMessageBox(
|
RPR_ShowMessageBox(
|
||||||
f'Exported text file "{output_file_name}" to project folder. Text Export Complete',
|
'Exported text file "%s" to project folder.' % output_file_name,
|
||||||
|
"Text Export Complete",
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from ptulsconv.commands import convert
|
|||||||
from ptulsconv.docparser.adr_entity import ADR_TAG_MAPPING, GENERIC_TAG_MAPPING
|
from ptulsconv.docparser.adr_entity import ADR_TAG_MAPPING, GENERIC_TAG_MAPPING
|
||||||
from ptulsconv.reporting import (
|
from ptulsconv.reporting import (
|
||||||
print_banner_style,
|
print_banner_style,
|
||||||
|
print_fatal_error,
|
||||||
print_section_header_style,
|
print_section_header_style,
|
||||||
print_status_style,
|
print_status_style,
|
||||||
)
|
)
|
||||||
@@ -101,7 +102,7 @@ def main():
|
|||||||
(options, args) = parser.parse_args(sys.argv)
|
(options, args) = parser.parse_args(sys.argv)
|
||||||
|
|
||||||
print_section_header_style("Startup")
|
print_section_header_style("Startup")
|
||||||
print_status_style(f"This run started {datetime.datetime.now().isoformat()}")
|
print_status_style("This run started %s" % (datetime.datetime.now().isoformat()))
|
||||||
|
|
||||||
if options.show_tags:
|
if options.show_tags:
|
||||||
dump_field_map()
|
dump_field_map()
|
||||||
@@ -110,16 +111,29 @@ def main():
|
|||||||
elif options.show_formats:
|
elif options.show_formats:
|
||||||
dump_formats()
|
dump_formats()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
try:
|
||||||
|
major_mode = options.output_format
|
||||||
|
|
||||||
major_mode = options.output_format
|
if len(args) < 2:
|
||||||
|
print_status_style(
|
||||||
|
"No input file provided, will connect to Pro Tools with PTSL..."
|
||||||
|
)
|
||||||
|
convert(major_mode=major_mode, warnings=options.warnings)
|
||||||
|
else:
|
||||||
|
convert(
|
||||||
|
input_file=args[1], major_mode=major_mode, warnings=options.warnings
|
||||||
|
)
|
||||||
|
|
||||||
if len(args) < 2:
|
except FileNotFoundError as e:
|
||||||
print_status_style(
|
print_fatal_error("Error trying to read input file")
|
||||||
"No input file provided, will connect to Pro Tools with PTSL..."
|
raise e
|
||||||
)
|
|
||||||
convert(major_mode=major_mode, warnings=options.warnings)
|
except Exception as e:
|
||||||
else:
|
import traceback
|
||||||
convert(input_file=args[1], major_mode=major_mode, warnings=options.warnings)
|
|
||||||
|
print_fatal_error("Error trying to convert file")
|
||||||
|
print("\033[31m" + e.__repr__() + "\033[0m", file=sys.stderr)
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -2,24 +2,21 @@
|
|||||||
Useful functions for parsing and working with timecode.
|
Useful functions for parsing and working with timecode.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
|
from collections import namedtuple
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from typing import NamedTuple
|
from typing import Optional, SupportsFloat
|
||||||
|
|
||||||
|
|
||||||
class TimecodeFormat(NamedTuple):
|
class TimecodeFormat(
|
||||||
|
namedtuple("_TimecodeFormat", "frame_duration logical_fps drop_frame")
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
A struct reperesenting a timecode datum.
|
A struct reperesenting a timecode datum.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
frame_duration: Fraction
|
def smpte_to_seconds(self, smpte: str) -> Optional[Fraction]:
|
||||||
logical_fps: int
|
|
||||||
drop_frame: bool
|
|
||||||
|
|
||||||
def smpte_to_seconds(self, smpte: str) -> Fraction | None:
|
|
||||||
frame_count = smpte_to_frame_count(
|
frame_count = smpte_to_frame_count(
|
||||||
smpte, self.logical_fps, drop_frame_hint=self.drop_frame
|
smpte, self.logical_fps, drop_frame_hint=self.drop_frame
|
||||||
)
|
)
|
||||||
@@ -28,14 +25,14 @@ class TimecodeFormat(NamedTuple):
|
|||||||
else:
|
else:
|
||||||
return frame_count * self.frame_duration
|
return frame_count * self.frame_duration
|
||||||
|
|
||||||
def seconds_to_smpte(self, seconds: Fraction) -> str:
|
def seconds_to_smpte(self, seconds: SupportsFloat) -> str:
|
||||||
frame_count = int(seconds / self.frame_duration)
|
frame_count = int(seconds / self.frame_duration)
|
||||||
return frame_count_to_smpte(frame_count, self.logical_fps, self.drop_frame)
|
return frame_count_to_smpte(frame_count, self.logical_fps, self.drop_frame)
|
||||||
|
|
||||||
|
|
||||||
def smpte_to_frame_count(
|
def smpte_to_frame_count(
|
||||||
smpte_rep_string: str, frames_per_logical_second: int, drop_frame_hint=False
|
smpte_rep_string: str, frames_per_logical_second: int, drop_frame_hint=False
|
||||||
) -> int | None:
|
) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
Convert a string with a SMPTE timecode representation into a frame count.
|
Convert a string with a SMPTE timecode representation into a frame count.
|
||||||
|
|
||||||
@@ -86,7 +83,7 @@ def frame_count_to_smpte(
|
|||||||
frame_count: int,
|
frame_count: int,
|
||||||
frames_per_logical_second: int,
|
frames_per_logical_second: int,
|
||||||
drop_frame: bool = False,
|
drop_frame: bool = False,
|
||||||
fractional_frame: float | None = None,
|
fractional_frame: Optional[float] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
assert frames_per_logical_second in [24, 25, 30, 48, 50, 60]
|
assert frames_per_logical_second in [24, 25, 30, 48, 50, 60]
|
||||||
assert fractional_frame is None or fractional_frame < 1.0
|
assert fractional_frame is None or fractional_frame < 1.0
|
||||||
@@ -107,21 +104,20 @@ def frame_count_to_smpte(
|
|||||||
ss, ff = divmod(rem, frames_per_logical_second)
|
ss, ff = divmod(rem, frames_per_logical_second)
|
||||||
|
|
||||||
hh = hh % 24
|
hh = hh % 24
|
||||||
|
|
||||||
hh = int(hh)
|
|
||||||
mm = int(mm)
|
|
||||||
ss = int(ss)
|
|
||||||
ff = int(ff)
|
|
||||||
|
|
||||||
if fractional_frame is not None and fractional_frame > 0:
|
if fractional_frame is not None and fractional_frame > 0:
|
||||||
fpart = "{fractional_frame:.3f}"[1:]
|
return "%02i:%02i:%02i%s%02i%s" % (
|
||||||
return f"{hh:02}:{mm:02}:{ss:02}{separator}{ff:02}{fpart}"
|
hh,
|
||||||
|
mm,
|
||||||
|
ss,
|
||||||
|
separator,
|
||||||
|
ff,
|
||||||
|
("%.3f" % fractional_frame)[1:],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return f"{hh:02}:{mm:02}:{ss:02}{separator}{ff:02}"
|
return "%02i:%02i:%02i%s%02i" % (hh, mm, ss, separator, ff)
|
||||||
# "%02i:%02i:%02i%s%02i" % (hh, mm, ss, separator, ff)
|
|
||||||
|
|
||||||
|
|
||||||
def footage_to_frame_count(footage_string) -> int | None:
|
def footage_to_frame_count(footage_string) -> Optional[int]:
|
||||||
m = re.search(r"(\d+)\+(\d+)(\.\d+)?", footage_string)
|
m = re.search(r"(\d+)\+(\d+)(\.\d+)?", footage_string)
|
||||||
if m is None:
|
if m is None:
|
||||||
return None
|
return None
|
||||||
@@ -135,4 +131,4 @@ def footage_to_frame_count(footage_string) -> int | None:
|
|||||||
|
|
||||||
def frame_count_to_footage(frame_count):
|
def frame_count_to_footage(frame_count):
|
||||||
feet, frm = divmod(frame_count, 16)
|
feet, frm = divmod(frame_count, 16)
|
||||||
return f"{feet}+{frm:02}"
|
return "%i+%02i" % (feet, frm)
|
||||||
|
|||||||
+21
-18
@@ -3,8 +3,6 @@ This module provides the main input document parsing and transform
|
|||||||
implementation.
|
implementation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
@@ -13,6 +11,7 @@ from collections.abc import Iterator
|
|||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
import ptsl
|
import ptsl
|
||||||
|
|
||||||
@@ -40,25 +39,26 @@ class FractionEncoder(JSONEncoder):
|
|||||||
as a dict.
|
as a dict.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
force_denominator: int | None
|
force_denominator: Optional[int]
|
||||||
|
|
||||||
def default(self, o):
|
def default(self, o):
|
||||||
|
""" """
|
||||||
if isinstance(o, Fraction):
|
if isinstance(o, Fraction):
|
||||||
return {"numerator": o.numerator, "denominator": o.denominator}
|
return dict(numerator=o.numerator, denominator=o.denominator)
|
||||||
else:
|
else:
|
||||||
return o.__dict__
|
return o.__dict__
|
||||||
|
|
||||||
|
|
||||||
def output_adr_csv(lines: list[ADRLine], time_format: TimecodeFormat):
|
def output_adr_csv(lines: List[ADRLine], time_format: TimecodeFormat):
|
||||||
"""
|
"""
|
||||||
Writes ADR lines as CSV to the current working directory. Creates
|
Writes ADR lines as CSV to the current working directory. Creates
|
||||||
directories for each character number and name pair, and within that
|
directories for each character number and name pair, and within that
|
||||||
directory, creates a CSV file for each reel.
|
directory, creates a CSV file for each reel.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
reels: set[str | None] = {ln.reel for ln in lines}
|
reels: set[str | None] = set([ln.reel for ln in lines])
|
||||||
for n, name in [(n.character_id, n.character_name) for n in lines]:
|
for n, name in [(n.character_id, n.character_name) for n in lines]:
|
||||||
dir_name = f"{n}_{name}"
|
dir_name = "%s_%s" % (n, name)
|
||||||
os.makedirs(dir_name, exist_ok=True)
|
os.makedirs(dir_name, exist_ok=True)
|
||||||
os.chdir(dir_name)
|
os.chdir(dir_name)
|
||||||
for reel in reels:
|
for reel in reels:
|
||||||
@@ -69,8 +69,11 @@ def output_adr_csv(lines: list[ADRLine], time_format: TimecodeFormat):
|
|||||||
if len(these_lines) == 0:
|
if len(these_lines) == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
outfile_name = (
|
outfile_name = "%s_%s_%s_%s.csv" % (
|
||||||
f"{these_lines[0].title}_{n}_{these_lines[0].character_name}_{reel}.csv"
|
these_lines[0].title,
|
||||||
|
n,
|
||||||
|
these_lines[0].character_name,
|
||||||
|
reel,
|
||||||
)
|
)
|
||||||
|
|
||||||
with open(outfile_name, mode="w", newline="") as outfile:
|
with open(outfile_name, mode="w", newline="") as outfile:
|
||||||
@@ -116,13 +119,13 @@ def output_adr_csv(lines: list[ADRLine], time_format: TimecodeFormat):
|
|||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def generate_documents(session_tc_format, scenes, adr_lines: list[ADRLine], title):
|
def generate_documents(session_tc_format, scenes, adr_lines: List[ADRLine], title):
|
||||||
"""
|
"""
|
||||||
Create PDF output.
|
Create PDF output.
|
||||||
"""
|
"""
|
||||||
print_section_header_style("Creating PDF Reports")
|
print_section_header_style("Creating PDF Reports")
|
||||||
report_date = datetime.datetime.now()
|
report_date = datetime.datetime.now()
|
||||||
reports_dir = f"{title}_{report_date.strftime('%Y-%m-%d_%H%M%S')}"
|
reports_dir = "%s_%s" % (title, report_date.strftime("%Y-%m-%d_%H%M%S"))
|
||||||
os.makedirs(reports_dir, exist_ok=False)
|
os.makedirs(reports_dir, exist_ok=False)
|
||||||
os.chdir(reports_dir)
|
os.chdir(reports_dir)
|
||||||
|
|
||||||
@@ -152,7 +155,7 @@ def generate_documents(session_tc_format, scenes, adr_lines: list[ADRLine], titl
|
|||||||
|
|
||||||
|
|
||||||
def create_adr_reports(
|
def create_adr_reports(
|
||||||
lines: list[ADRLine], tc_display_format: TimecodeFormat, reel_list: list[str]
|
lines: List[ADRLine], tc_display_format: TimecodeFormat, reel_list: List[str]
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a directory heirarchy and a respective set of ADR reports,
|
Creates a directory heirarchy and a respective set of ADR reports,
|
||||||
@@ -237,18 +240,18 @@ def convert(major_mode, input_file=None, output=sys.stdout, warnings=True):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Breakdown by titles
|
# TODO: Breakdown by titles
|
||||||
titles = {x.title for x in (generic_events + adr_lines)}
|
titles = set([x.title for x in (generic_events + adr_lines)])
|
||||||
if len(titles) != 1:
|
if len(titles) != 1:
|
||||||
print_warning(
|
print_warning(
|
||||||
"Multiple titles per export is not supported, "
|
"Multiple titles per export is not supported, "
|
||||||
f"found multiple titles: {titles} Exiting."
|
"found multiple titles: %s Exiting." % titles
|
||||||
)
|
)
|
||||||
sys.exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
title = next(iter(titles))
|
title = list(titles)[0]
|
||||||
|
|
||||||
print_status_style(f"{len(generic_events)} generic events found.")
|
print_status_style("%i generic events found." % len(generic_events))
|
||||||
print_status_style(f"{len(adr_lines)} ADR events found.")
|
print_status_style("%i ADR events found." % len(adr_lines))
|
||||||
|
|
||||||
if warnings:
|
if warnings:
|
||||||
perform_adr_validations(iter(adr_lines))
|
perform_adr_validations(iter(adr_lines))
|
||||||
|
|||||||
@@ -2,4 +2,7 @@
|
|||||||
Docparser module
|
Docparser module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .pt_doc_parser import parse_document # pyright: ignore[reportUnusedImport, reportUnusedImport] # noqa: F401, I001
|
|
||||||
|
from .pt_doc_parser import parse_document
|
||||||
|
|
||||||
|
__all__ = [parse_document]
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
from collections.abc import Generator, Iterator
|
from collections.abc import Generator, Iterator
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from typing import Callable, NamedTuple
|
from typing import Callable
|
||||||
|
|
||||||
from ptulsconv.docparser import doc_entity
|
from ptulsconv.docparser import doc_entity
|
||||||
|
|
||||||
@@ -26,15 +27,12 @@ class TagCompiler:
|
|||||||
items.
|
items.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Intermediate(NamedTuple):
|
Intermediate = namedtuple(
|
||||||
track_content: str
|
"Intermediate",
|
||||||
clip_content: str
|
"track_content track_tags track_comment_tags "
|
||||||
track_tags: dict[str, str]
|
"clip_content clip_tags clip_tag_mode start "
|
||||||
track_comment_tags: dict[str, str]
|
"finish",
|
||||||
clip_tags: dict[str, str]
|
)
|
||||||
clip_tag_mode: TagPreModes
|
|
||||||
start: Fraction
|
|
||||||
finish: Fraction
|
|
||||||
|
|
||||||
session: doc_entity.SessionDescriptor
|
session: doc_entity.SessionDescriptor
|
||||||
|
|
||||||
@@ -133,6 +131,7 @@ class TagCompiler:
|
|||||||
return effective_tags
|
return effective_tags
|
||||||
|
|
||||||
def parse_data(self) -> Iterator[Intermediate]:
|
def parse_data(self) -> Iterator[Intermediate]:
|
||||||
|
|
||||||
for track, clip, start, finish, _ in self.session.track_clips_timed():
|
for track, clip, start, finish, _ in self.session.track_clips_timed():
|
||||||
if clip.state == "Muted":
|
if clip.state == "Muted":
|
||||||
continue
|
continue
|
||||||
@@ -154,6 +153,7 @@ class TagCompiler:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def apply_appends(parsed: Iterator[Intermediate]) -> Iterator[Intermediate]:
|
def apply_appends(parsed: Iterator[Intermediate]) -> Iterator[Intermediate]:
|
||||||
|
|
||||||
def should_append(a, b):
|
def should_append(a, b):
|
||||||
return b.clip_tag_mode == TagPreModes.APPEND and b.start >= a.finish
|
return b.clip_tag_mode == TagPreModes.APPEND and b.start >= a.finish
|
||||||
|
|
||||||
@@ -177,13 +177,14 @@ class TagCompiler:
|
|||||||
def collect_time_spans(
|
def collect_time_spans(
|
||||||
parsed: Iterator[Intermediate],
|
parsed: Iterator[Intermediate],
|
||||||
) -> Iterator[tuple[Intermediate, tuple[dict, Fraction, Fraction]]]:
|
) -> Iterator[tuple[Intermediate, tuple[dict, Fraction, Fraction]]]:
|
||||||
|
|
||||||
time_spans = []
|
time_spans = []
|
||||||
|
|
||||||
for item in parsed:
|
for item in parsed:
|
||||||
if item.clip_tag_mode == TagPreModes.TIMESPAN:
|
if item.clip_tag_mode == TagPreModes.TIMESPAN:
|
||||||
time_spans.append((item.clip_tags, item.start, item.finish))
|
time_spans.append((item.clip_tags, item.start, item.finish))
|
||||||
else:
|
else:
|
||||||
yield item, tuple(time_spans)
|
yield item, list(time_spans)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _time_span_tags(at_time: Fraction, applicable_spans) -> dict:
|
def _time_span_tags(at_time: Fraction, applicable_spans) -> dict:
|
||||||
@@ -198,6 +199,7 @@ class TagCompiler:
|
|||||||
def apply_tags(
|
def apply_tags(
|
||||||
self, parsed_with_time_spans
|
self, parsed_with_time_spans
|
||||||
) -> Iterator[tuple[str, str, str, dict, Fraction, Fraction]]:
|
) -> Iterator[tuple[str, str, str, dict, Fraction, Fraction]]:
|
||||||
|
|
||||||
session_parsed = parse_tags(self.session.header.session_name)
|
session_parsed = parse_tags(self.session.header.session_name)
|
||||||
|
|
||||||
for event, time_spans in parsed_with_time_spans:
|
for event, time_spans in parsed_with_time_spans:
|
||||||
@@ -224,13 +226,13 @@ class TagCompiler:
|
|||||||
|
|
||||||
|
|
||||||
def apply_appends(
|
def apply_appends(
|
||||||
source: Iterator, should_append: Callable, preform_append: Callable
|
source: Iterator, should_append: Callable, do_append: Callable
|
||||||
) -> Generator:
|
) -> Generator:
|
||||||
"""
|
"""
|
||||||
:param source:
|
:param source:
|
||||||
:param should_append: Called with two variables a and b, your
|
:param should_append: Called with two variables a and b, your
|
||||||
function should return true if b should be
|
function should return true if b should be
|
||||||
appended to a
|
appended to a
|
||||||
:param do_append: Called with two variables a and b, your function
|
:param do_append: Called with two variables a and b, your function
|
||||||
should return
|
should return
|
||||||
:returns: A Generator
|
:returns: A Generator
|
||||||
@@ -238,7 +240,7 @@ def apply_appends(
|
|||||||
this_element = next(source)
|
this_element = next(source)
|
||||||
for element in source:
|
for element in source:
|
||||||
if should_append(this_element, element):
|
if should_append(this_element, element):
|
||||||
this_element = preform_append(this_element, element)
|
this_element = do_append(this_element, element)
|
||||||
else:
|
else:
|
||||||
yield this_element
|
yield this_element
|
||||||
this_element = element
|
this_element = element
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from parsimonious import Grammar, NodeVisitor
|
from parsimonious import Grammar, NodeVisitor
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ def parse_tags(prompt: str) -> "TaggedStringResult":
|
|||||||
|
|
||||||
class TaggedStringResult:
|
class TaggedStringResult:
|
||||||
content: str
|
content: str
|
||||||
tag_dict: dict[str, str]
|
tag_dict: Dict[str, str]
|
||||||
mode: TagPreModes
|
mode: TagPreModes
|
||||||
|
|
||||||
def __init__(self, content, tag_dict, mode):
|
def __init__(self, content, tag_dict, mode):
|
||||||
@@ -52,7 +53,7 @@ class TagListVisitor(NodeVisitor):
|
|||||||
|
|
||||||
return TaggedStringResult(
|
return TaggedStringResult(
|
||||||
content=next(iter(line_opt), None),
|
content=next(iter(line_opt), None),
|
||||||
tag_dict=next(iter(tag_list_opt), {}),
|
tag_dict=next(iter(tag_list_opt), dict()),
|
||||||
mode=TagPreModes(next(iter(modifier_opt), "Normal")),
|
mode=TagPreModes(next(iter(modifier_opt), "Normal")),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ class TagListVisitor(NodeVisitor):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def visit_tag_list(_, visited_children):
|
def visit_tag_list(_, visited_children):
|
||||||
retdict = {}
|
retdict = dict()
|
||||||
for child in visited_children:
|
for child in visited_children:
|
||||||
if child[0] is not None:
|
if child[0] is not None:
|
||||||
k, v = child[0]
|
k, v = child[0]
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
Methods for converting string reprentations of film footage.
|
Methods for converting string reprentations of film footage.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
def footage_to_seconds(footage: str) -> Fraction | None:
|
def footage_to_seconds(footage: str) -> Optional[Fraction]:
|
||||||
"""
|
"""
|
||||||
Converts a string representation of a footage (35mm, 24fps)
|
Converts a string representation of a footage (35mm, 24fps)
|
||||||
into a :class:`Fraction`, this fraction being a some number of
|
into a :class:`Fraction`, this fraction being a some number of
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ReportCanvas(canvas.Canvas):
|
|||||||
|
|
||||||
def showPage(self):
|
def showPage(self):
|
||||||
self._saved_page_states.append(dict(self.__dict__))
|
self._saved_page_states.append(dict(self.__dict__))
|
||||||
self._startPage() # pyright: ignore[reportAttributeAccessIssue]
|
self._startPage()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""add page info to each page (page x of y)"""
|
"""add page info to each page (page x of y)"""
|
||||||
@@ -41,11 +41,9 @@ class ReportCanvas(canvas.Canvas):
|
|||||||
self.saveState()
|
self.saveState()
|
||||||
self.setFont("Helvetica", 10) # FIXME make this customizable
|
self.setFont("Helvetica", 10) # FIXME make this customizable
|
||||||
self.drawString(
|
self.drawString(
|
||||||
0.5 * inch,
|
0.5 * inch, 0.5 * inch, "Page %d of %d" % (self._pageNumber, page_count)
|
||||||
0.5 * inch,
|
|
||||||
f"Page {self._pageNumber} of {page_count}", # pyright: ignore[reportAttributeAccessIssue]
|
|
||||||
)
|
)
|
||||||
right_edge = self._pagesize[0] - 0.5 * inch # pyright: ignore[reportAttributeAccessIssue]
|
right_edge = self._pagesize[0] - 0.5 * inch
|
||||||
self.drawRightString(
|
self.drawRightString(
|
||||||
right_edge, 0.5 * inch, self._report_date.strftime("%m/%d/%Y %H:%M")
|
right_edge, 0.5 * inch, self._report_date.strftime("%m/%d/%Y %H:%M")
|
||||||
)
|
)
|
||||||
@@ -64,7 +62,7 @@ class ADRDocTemplate(BaseDocTemplate):
|
|||||||
|
|
||||||
|
|
||||||
def make_doc_template(
|
def make_doc_template(
|
||||||
page_size: tuple[float, float],
|
page_size,
|
||||||
filename,
|
filename,
|
||||||
document_title,
|
document_title,
|
||||||
title: str,
|
title: str,
|
||||||
@@ -73,22 +71,18 @@ def make_doc_template(
|
|||||||
client: str,
|
client: str,
|
||||||
document_subheader: str,
|
document_subheader: str,
|
||||||
left_margin=0.5 * inch,
|
left_margin=0.5 * inch,
|
||||||
fonts: list[TTFont] | None = None,
|
fonts: list[TTFont] = [],
|
||||||
) -> ADRDocTemplate:
|
) -> ADRDocTemplate:
|
||||||
|
|
||||||
if fonts is None:
|
|
||||||
fonts = []
|
|
||||||
|
|
||||||
right_margin = top_margin = bottom_margin = 0.5 * inch
|
right_margin = top_margin = bottom_margin = 0.5 * inch
|
||||||
page_box: GRect = GRect(0.0, 0.0, page_size[0], page_size[1])
|
page_box: GRect = GRect(0.0, 0.0, page_size[0], page_size[1])
|
||||||
_, page_box = page_box.split_x(left_margin, direction="l") # pyright: ignore[reportAssignmentType]
|
_, page_box = page_box.split_x(left_margin, direction="l")
|
||||||
_, page_box = page_box.split_x(right_margin, direction="r") # pyright: ignore[reportAssignmentType]
|
_, page_box = page_box.split_x(right_margin, direction="r")
|
||||||
_, page_box = page_box.split_y(bottom_margin, direction="u") # pyright: ignore[reportAssignmentType]
|
_, page_box = page_box.split_y(bottom_margin, direction="u")
|
||||||
_, page_box = page_box.split_y(top_margin, direction="d") # pyright: ignore[reportAssignmentType]
|
_, page_box = page_box.split_y(top_margin, direction="d")
|
||||||
|
|
||||||
footer_box, page_box = page_box.split_y(0.25 * inch, direction="u") # pyright: ignore[reportAssignmentType]
|
footer_box, page_box = page_box.split_y(0.25 * inch, direction="u")
|
||||||
header_box, page_box = page_box.split_y(0.75 * inch, direction="d") # pyright: ignore[reportAssignmentType]
|
header_box, page_box = page_box.split_y(0.75 * inch, direction="d")
|
||||||
title_box, report_box = header_box.split_x(3.5 * inch, direction="r") # pyright: ignore[reportOptionalMemberAccess]
|
title_box, report_box = header_box.split_x(3.5 * inch, direction="r")
|
||||||
|
|
||||||
def on_page_lambda(c, _):
|
def on_page_lambda(c, _):
|
||||||
draw_header_footer(
|
draw_header_footer(
|
||||||
@@ -103,6 +97,7 @@ def make_doc_template(
|
|||||||
doc_title=document_header,
|
doc_title=document_header,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
frames = [Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)]
|
frames = [Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)]
|
||||||
|
|
||||||
page_template = PageTemplate(id="Main", frames=frames, onPage=on_page_lambda)
|
page_template = PageTemplate(id="Main", frames=frames, onPage=on_page_lambda)
|
||||||
@@ -297,7 +292,7 @@ class GRect:
|
|||||||
|
|
||||||
rem = self
|
rem = self
|
||||||
for item in x_list:
|
for item in x_list:
|
||||||
s, rem = rem.split_x(item, direction) # pyright: ignore[reportOptionalMemberAccess]
|
s, rem = rem.split_x(item, direction)
|
||||||
ret_list.append(s)
|
ret_list.append(s)
|
||||||
|
|
||||||
return ret_list, rem
|
return ret_list, rem
|
||||||
@@ -307,7 +302,7 @@ class GRect:
|
|||||||
|
|
||||||
rem = self
|
rem = self
|
||||||
for item in y_list:
|
for item in y_list:
|
||||||
s, rem = rem.split_y(item, direction) # pyright: ignore[reportOptionalMemberAccess]
|
s, rem = rem.split_y(item, direction)
|
||||||
ret_list.append(s)
|
ret_list.append(s)
|
||||||
|
|
||||||
return ret_list, rem
|
return ret_list, rem
|
||||||
@@ -404,7 +399,7 @@ class GRect:
|
|||||||
cp.rect(self.min_x, self.min_y, self.width, self.height)
|
cp.rect(self.min_x, self.min_y, self.width, self.height)
|
||||||
a_canvas.clipPath(cp, stroke=0, fill=0)
|
a_canvas.clipPath(cp, stroke=0, fill=0)
|
||||||
|
|
||||||
_w, h = flowable.wrap(inset_rect.width, inset_rect.height)
|
w, h = flowable.wrap(inset_rect.width, inset_rect.height)
|
||||||
|
|
||||||
flowable.drawOn(a_canvas, inset_rect.x, inset_rect.max_y - h)
|
flowable.drawOn(a_canvas, inset_rect.x, inset_rect.max_y - h)
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def table_for_scene(scene, tc_format, font_name="Helvetica"):
|
|||||||
scene_style.spaceAfter = 18.0
|
scene_style.spaceAfter = 18.0
|
||||||
|
|
||||||
tc_data = f"<em>{tc_format.seconds_to_smpte(scene[2])}</em><br />{tc_format.seconds_to_smpte(scene[3])}"
|
tc_data = f"<em>{tc_format.seconds_to_smpte(scene[2])}</em><br />{tc_format.seconds_to_smpte(scene[3])}"
|
||||||
|
|
||||||
row = [
|
row = [
|
||||||
Paragraph(tc_data, scene_style),
|
Paragraph(tc_data, scene_style),
|
||||||
Paragraph(scene[1], scene_style),
|
Paragraph(scene[1], scene_style),
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
from __future__ import annotations
|
from typing import List, Optional
|
||||||
|
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
from reportlab.lib.pagesizes import letter, portrait
|
from reportlab.lib.pagesizes import letter, portrait
|
||||||
from reportlab.lib.styles import getSampleStyleSheet
|
from reportlab.lib.styles import getSampleStyleSheet
|
||||||
|
|
||||||
|
# from reportlab.pdfbase import pdfmetrics
|
||||||
|
# from reportlab.pdfbase.ttfonts import TTFont
|
||||||
from reportlab.lib.units import inch
|
from reportlab.lib.units import inch
|
||||||
from reportlab.platypus import Paragraph, Spacer, Table
|
from reportlab.platypus import Paragraph, Spacer, Table
|
||||||
|
|
||||||
@@ -11,13 +14,15 @@ from .__init__ import make_doc_template, time_format
|
|||||||
|
|
||||||
|
|
||||||
def build_columns(
|
def build_columns(
|
||||||
lines: list[ADRLine],
|
lines: List[ADRLine],
|
||||||
reel_list: list[str] | None,
|
reel_list: Optional[List[str]],
|
||||||
show_priorities=False,
|
show_priorities=False,
|
||||||
include_omitted=False,
|
include_omitted=False,
|
||||||
):
|
):
|
||||||
columns = []
|
columns = list()
|
||||||
reel_numbers = reel_list or sorted({x.reel for x in lines if x.reel is not None})
|
reel_numbers = reel_list or sorted(
|
||||||
|
set([x.reel for x in lines if x.reel is not None])
|
||||||
|
)
|
||||||
|
|
||||||
num_column_width = 15.0 / 32.0 * inch
|
num_column_width = 15.0 / 32.0 * inch
|
||||||
|
|
||||||
@@ -155,17 +160,17 @@ def build_columns(
|
|||||||
):
|
):
|
||||||
columns.append(
|
columns.append(
|
||||||
{
|
{
|
||||||
"heading": f"P{n}",
|
"heading": "P%i" % n,
|
||||||
"value_getter": lambda recs, N=n: len(
|
"value_getter": lambda recs: len(
|
||||||
[r for r in recs if r.priority == N]
|
[r for r in recs if r.priority == n]
|
||||||
),
|
),
|
||||||
"value_getter2": (
|
"value_getter2": (
|
||||||
lambda recs, N=n: time_format(
|
lambda recs: time_format(
|
||||||
sum(
|
sum(
|
||||||
[
|
[
|
||||||
r.time_budget_mins or 0.0
|
r.time_budget_mins or 0.0
|
||||||
for r in recs
|
for r in recs
|
||||||
if r.priority == N
|
if r.priority == n
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -238,20 +243,22 @@ def build_columns(
|
|||||||
return columns
|
return columns
|
||||||
|
|
||||||
|
|
||||||
def populate_columns(lines: list[ADRLine], columns, include_omitted, _page_size):
|
def populate_columns(lines: List[ADRLine], columns, include_omitted, _page_size):
|
||||||
data = []
|
data = list()
|
||||||
styles = []
|
styles = list()
|
||||||
columns_widths = []
|
columns_widths = list()
|
||||||
|
|
||||||
sorted_character_numbers: list[str | None] = sorted(
|
sorted_character_numbers: List[str] = sorted(
|
||||||
{x.character_id for x in lines}, key=lambda x: str(x)
|
set([x.character_id for x in lines]), key=lambda x: str(x)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# construct column styles
|
||||||
|
|
||||||
for i, c in enumerate(columns):
|
for i, c in enumerate(columns):
|
||||||
styles.extend(c["style_getter"](i))
|
styles.extend(c["style_getter"](i))
|
||||||
columns_widths.append(c["width"])
|
columns_widths.append(c["width"])
|
||||||
|
|
||||||
data.append([x["heading"] for x in columns])
|
data.append(list(map(lambda x: x["heading"], columns)))
|
||||||
|
|
||||||
if not include_omitted:
|
if not include_omitted:
|
||||||
lines = [x for x in lines if not x.omitted]
|
lines = [x for x in lines if not x.omitted]
|
||||||
@@ -259,8 +266,8 @@ def populate_columns(lines: list[ADRLine], columns, include_omitted, _page_size)
|
|||||||
for n in sorted_character_numbers:
|
for n in sorted_character_numbers:
|
||||||
char_records = [x for x in lines if x.character_id == n]
|
char_records = [x for x in lines if x.character_id == n]
|
||||||
if len(char_records) > 0:
|
if len(char_records) > 0:
|
||||||
row_data = []
|
row_data = list()
|
||||||
row_data2 = []
|
row_data2 = list()
|
||||||
|
|
||||||
for col in columns:
|
for col in columns:
|
||||||
row1_index = len(data)
|
row1_index = len(data)
|
||||||
@@ -284,8 +291,8 @@ def populate_columns(lines: list[ADRLine], columns, include_omitted, _page_size)
|
|||||||
data.append(row_data)
|
data.append(row_data)
|
||||||
data.append(row_data2)
|
data.append(row_data2)
|
||||||
|
|
||||||
summary_row1 = []
|
summary_row1 = list()
|
||||||
summary_row2 = []
|
summary_row2 = list()
|
||||||
row1_index = len(data)
|
row1_index = len(data)
|
||||||
|
|
||||||
for col in columns:
|
for col in columns:
|
||||||
@@ -309,15 +316,12 @@ def populate_columns(lines: list[ADRLine], columns, include_omitted, _page_size)
|
|||||||
|
|
||||||
|
|
||||||
def output_report(
|
def output_report(
|
||||||
lines: list[ADRLine],
|
lines: List[ADRLine],
|
||||||
reel_list: list[str],
|
reel_list: List[str],
|
||||||
page_size: tuple[float, float] | None = None,
|
|
||||||
include_omitted=False,
|
include_omitted=False,
|
||||||
|
page_size=portrait(letter),
|
||||||
font_name="Helvetica",
|
font_name="Helvetica",
|
||||||
):
|
):
|
||||||
if page_size is None:
|
|
||||||
page_size = portrait(letter)
|
|
||||||
|
|
||||||
columns = build_columns(lines, include_omitted=include_omitted, reel_list=reel_list)
|
columns = build_columns(lines, include_omitted=include_omitted, reel_list=reel_list)
|
||||||
data, style, columns_widths = populate_columns(
|
data, style, columns_widths = populate_columns(
|
||||||
lines, columns, include_omitted, page_size
|
lines, columns, include_omitted, page_size
|
||||||
@@ -330,17 +334,16 @@ def output_report(
|
|||||||
|
|
||||||
# pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
# pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
||||||
|
|
||||||
title = f"{lines[0].title} Line Count"
|
title = "%s Line Count" % lines[0].title
|
||||||
filename = title + ".pdf"
|
filename = title + ".pdf"
|
||||||
|
|
||||||
doc = make_doc_template(
|
doc = make_doc_template(
|
||||||
page_size=page_size,
|
page_size=page_size,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
document_title=title,
|
document_title=title,
|
||||||
title=lines[0].title,
|
title=lines[0].title,
|
||||||
document_subheader=lines[0].spot or "",
|
document_subheader=lines[0].spot,
|
||||||
client=lines[0].client or "",
|
client=lines[0].client,
|
||||||
supervisor=lines[0].supervisor or "",
|
supervisor=lines[0].supervisor,
|
||||||
document_header="Line Count",
|
document_header="Line Count",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -361,6 +364,8 @@ def output_report(
|
|||||||
omitted_count = len([x for x in lines if x.omitted])
|
omitted_count = len([x for x in lines if x.omitted])
|
||||||
|
|
||||||
if not include_omitted and omitted_count > 0:
|
if not include_omitted and omitted_count > 0:
|
||||||
story.append(Paragraph(f"* {omitted_count} Omitted lines are excluded.", style))
|
story.append(
|
||||||
|
Paragraph("* %i Omitted lines are excluded." % omitted_count, style)
|
||||||
|
)
|
||||||
|
|
||||||
doc.build(story)
|
doc.build(story)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from reportlab.lib.pagesizes import letter, portrait
|
from reportlab.lib.pagesizes import letter, portrait
|
||||||
from reportlab.lib.styles import getSampleStyleSheet
|
from reportlab.lib.styles import getSampleStyleSheet
|
||||||
@@ -12,7 +13,7 @@ from .__init__ import make_doc_template, time_format
|
|||||||
|
|
||||||
|
|
||||||
def build_aux_data_field(line: ADRLine):
|
def build_aux_data_field(line: ADRLine):
|
||||||
entries = []
|
entries = list()
|
||||||
if line.reason is not None:
|
if line.reason is not None:
|
||||||
entries.append("Reason: " + line.reason)
|
entries.append("Reason: " + line.reason)
|
||||||
if line.note is not None:
|
if line.note is not None:
|
||||||
@@ -26,30 +27,40 @@ def build_aux_data_field(line: ADRLine):
|
|||||||
tag_field = ""
|
tag_field = ""
|
||||||
if line.effort:
|
if line.effort:
|
||||||
bg_color = "red"
|
bg_color = "red"
|
||||||
tag_field += (
|
tag_field += "<font backColor=%s textColor=%s fontSize=11>%s</font> " % (
|
||||||
f"<font backColor={bg_color} textColor={fg_color} fontSize=11>EFF</font> "
|
bg_color,
|
||||||
|
fg_color,
|
||||||
|
"EFF",
|
||||||
)
|
)
|
||||||
elif line.tv:
|
elif line.tv:
|
||||||
bg_color = "blue"
|
bg_color = "blue"
|
||||||
tag_field += (
|
tag_field += "<font backColor=%s textColor=%s fontSize=11>%s</font> " % (
|
||||||
f"<font backColor={bg_color} textColor={fg_color} fontSize=11>TV</font> "
|
bg_color,
|
||||||
|
fg_color,
|
||||||
|
"TV",
|
||||||
)
|
)
|
||||||
elif line.adlib:
|
elif line.adlib:
|
||||||
bg_color = "purple"
|
bg_color = "purple"
|
||||||
tag_field += (
|
tag_field += "<font backColor=%s textColor=%s fontSize=11>%s</font> " % (
|
||||||
f"<font backColor={bg_color} textColor={fg_color} fontSize=11>ADLIB</font> "
|
bg_color,
|
||||||
|
fg_color,
|
||||||
|
"ADLIB",
|
||||||
)
|
)
|
||||||
elif line.optional:
|
elif line.optional:
|
||||||
bg_color = "green"
|
bg_color = "green"
|
||||||
tag_field += f"font backColor={bg_color} textColor={fg_color} fontSize=11>OPTIONAL</font>"
|
tag_field += "<font backColor=%s textColor=%s fontSize=11>%s</font>" % (
|
||||||
|
bg_color,
|
||||||
|
fg_color,
|
||||||
|
"OPTIONAL",
|
||||||
|
)
|
||||||
|
|
||||||
entries.append(tag_field)
|
entries.append(tag_field)
|
||||||
|
|
||||||
return "<br />".join(entries)
|
return "<br />".join(entries)
|
||||||
|
|
||||||
|
|
||||||
def build_story(lines: list[ADRLine], tc_rate: TimecodeFormat, font_name="Helvetica"):
|
def build_story(lines: List[ADRLine], tc_rate: TimecodeFormat, font_name="Helvetica"):
|
||||||
story = []
|
story = list()
|
||||||
|
|
||||||
this_scene = None
|
this_scene = None
|
||||||
scene_style = getSampleStyleSheet()["Normal"]
|
scene_style = getSampleStyleSheet()["Normal"]
|
||||||
@@ -67,14 +78,15 @@ def build_story(lines: list[ADRLine], tc_rate: TimecodeFormat, font_name="Helvet
|
|||||||
("BOTTOMPADDING", (0, 0), (-1, -1), 24.0),
|
("BOTTOMPADDING", (0, 0), (-1, -1), 24.0),
|
||||||
]
|
]
|
||||||
|
|
||||||
cue_number_field = (
|
cue_number_field = "%s<br /><font fontSize=7>%s</font>" % (
|
||||||
f"{line.cue_number}<br /><font fontSize=7>{line.character_name}</font>"
|
line.cue_number,
|
||||||
|
line.character_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
time_data = time_format(line.time_budget_mins)
|
time_data = time_format(line.time_budget_mins)
|
||||||
|
|
||||||
if line.priority is not None:
|
if line.priority is not None:
|
||||||
time_data = time_data + "<br />" + "P: " + str(line.priority)
|
time_data = time_data + "<br />" + "P: " + line.priority
|
||||||
|
|
||||||
aux_data_field = build_aux_data_field(line)
|
aux_data_field = build_aux_data_field(line)
|
||||||
|
|
||||||
@@ -84,7 +96,7 @@ def build_story(lines: list[ADRLine], tc_rate: TimecodeFormat, font_name="Helvet
|
|||||||
[
|
[
|
||||||
Paragraph(cue_number_field, line_style),
|
Paragraph(cue_number_field, line_style),
|
||||||
Paragraph(tc_data, line_style),
|
Paragraph(tc_data, line_style),
|
||||||
Paragraph(line.prompt or "[No Prompt]", line_style),
|
Paragraph(line.prompt, line_style),
|
||||||
Paragraph(time_data, line_style),
|
Paragraph(time_data, line_style),
|
||||||
Paragraph(aux_data_field, line_style),
|
Paragraph(aux_data_field, line_style),
|
||||||
]
|
]
|
||||||
@@ -123,11 +135,11 @@ def build_tc_data(line: ADRLine, tc_format: TimecodeFormat):
|
|||||||
third_line = []
|
third_line = []
|
||||||
if line.reel is not None:
|
if line.reel is not None:
|
||||||
if line.reel[0:1] == "R":
|
if line.reel[0:1] == "R":
|
||||||
third_line.append(f"{line.reel}")
|
third_line.append("%s" % line.reel)
|
||||||
else:
|
else:
|
||||||
third_line.append(f"Reel {line.reel}")
|
third_line.append("Reel %s" % line.reel)
|
||||||
if line.version is not None:
|
if line.version is not None:
|
||||||
third_line.append(f"({line.version})")
|
third_line.append("(%s)" % line.version)
|
||||||
if len(third_line) > 0:
|
if len(third_line) > 0:
|
||||||
tc_data = tc_data + "<br/>" + " ".join(third_line)
|
tc_data = tc_data + "<br/>" + " ".join(third_line)
|
||||||
return tc_data
|
return tc_data
|
||||||
@@ -135,17 +147,17 @@ def build_tc_data(line: ADRLine, tc_format: TimecodeFormat):
|
|||||||
|
|
||||||
def generate_report(
|
def generate_report(
|
||||||
page_size,
|
page_size,
|
||||||
lines: list[ADRLine],
|
lines: List[ADRLine],
|
||||||
tc_rate: TimecodeFormat,
|
tc_rate: TimecodeFormat,
|
||||||
character_number=None,
|
character_number=None,
|
||||||
include_omitted=True,
|
include_omitted=True,
|
||||||
):
|
):
|
||||||
if character_number is not None:
|
if character_number is not None:
|
||||||
lines = [r for r in lines if r.character_id == character_number]
|
lines = [r for r in lines if r.character_id == character_number]
|
||||||
title = f"{lines[0].title} ADR Report ({lines[0].character_name})"
|
title = "%s ADR Report (%s)" % (lines[0].title, lines[0].character_name)
|
||||||
document_header = f"{lines[0].character_name} ADR Report"
|
document_header = "%s ADR Report" % lines[0].character_name
|
||||||
else:
|
else:
|
||||||
title = f"{lines[0].title} ADR Report"
|
title = "%s ADR Report" % lines[0].title
|
||||||
document_header = "ADR Report"
|
document_header = "ADR Report"
|
||||||
|
|
||||||
if not include_omitted:
|
if not include_omitted:
|
||||||
@@ -160,9 +172,9 @@ def generate_report(
|
|||||||
document_title=title,
|
document_title=title,
|
||||||
document_header=document_header,
|
document_header=document_header,
|
||||||
title=lines[0].title,
|
title=lines[0].title,
|
||||||
supervisor=lines[0].supervisor or "",
|
supervisor=lines[0].supervisor,
|
||||||
client=lines[0].client or "",
|
client=lines[0].client,
|
||||||
document_subheader=lines[0].spot or "",
|
document_subheader=lines[0].spot,
|
||||||
left_margin=0.75 * inch,
|
left_margin=0.75 * inch,
|
||||||
)
|
)
|
||||||
story = build_story(lines, tc_rate)
|
story = build_story(lines, tc_rate)
|
||||||
@@ -170,16 +182,13 @@ def generate_report(
|
|||||||
|
|
||||||
|
|
||||||
def output_report(
|
def output_report(
|
||||||
lines: list[ADRLine],
|
lines: List[ADRLine],
|
||||||
tc_display_format: TimecodeFormat,
|
tc_display_format: TimecodeFormat,
|
||||||
page_size: tuple[float, float] | None = None,
|
page_size=portrait(letter),
|
||||||
by_character: bool = False,
|
by_character=False,
|
||||||
):
|
):
|
||||||
if page_size is None:
|
|
||||||
page_size = portrait(letter)
|
|
||||||
|
|
||||||
if by_character:
|
if by_character:
|
||||||
character_numbers = {r.character_id for r in lines}
|
character_numbers = set(r.character_id for r in lines)
|
||||||
for n in character_numbers:
|
for n in character_numbers:
|
||||||
generate_report(page_size, lines, tc_display_format, n)
|
generate_report(page_size, lines, tc_display_format, n)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def draw_header_block(canvas, rect, record: ADRLine):
|
|||||||
def draw_character_row(canvas, rect, record: ADRLine):
|
def draw_character_row(canvas, rect, record: ADRLine):
|
||||||
label_frame, value_frame = rect.split_x(1.25 * inch)
|
label_frame, value_frame = rect.split_x(1.25 * inch)
|
||||||
label_frame.draw_text_cell(canvas, "CHARACTER", font_name, 10, force_baseline=9.0)
|
label_frame.draw_text_cell(canvas, "CHARACTER", font_name, 10, force_baseline=9.0)
|
||||||
line = f"{record.character_id} / {record.character_name}"
|
line = "%s / %s" % (record.character_id, record.character_name)
|
||||||
if record.actor_name is not None:
|
if record.actor_name is not None:
|
||||||
line = line + " / " + record.actor_name
|
line = line + " / " + record.actor_name
|
||||||
value_frame.draw_text_cell(canvas, line, font_name, 12, force_baseline=9.0)
|
value_frame.draw_text_cell(canvas, line, font_name, 12, force_baseline=9.0)
|
||||||
@@ -61,9 +61,9 @@ def draw_cue_number_block(canvas, rect, record: ADRLine):
|
|||||||
"omitted": "OMIT",
|
"omitted": "OMIT",
|
||||||
}
|
}
|
||||||
tag_field = ""
|
tag_field = ""
|
||||||
for key, value in tags.items():
|
for key in tags:
|
||||||
if getattr(record, key):
|
if getattr(record, key):
|
||||||
tag_field = tag_field + value + " "
|
tag_field = tag_field + tags[key] + " "
|
||||||
|
|
||||||
aux_frame.draw_text_cell(
|
aux_frame.draw_text_cell(
|
||||||
canvas, tag_field, font_name, 10, inset_x=10.0, inset_y=2.0, vertical_align="t"
|
canvas, tag_field, font_name, 10, inset_x=10.0, inset_y=2.0, vertical_align="t"
|
||||||
@@ -221,7 +221,7 @@ def draw_aux_block(canvas, rect, recording_time_sec_this_line, recording_time_se
|
|||||||
rect.draw_border(canvas, "min_x")
|
rect.draw_border(canvas, "min_x")
|
||||||
|
|
||||||
content_rect = rect.inset_xy(10.0, 10.0)
|
content_rect = rect.inset_xy(10.0, 10.0)
|
||||||
lines, _ = content_rect.divide_y(
|
lines, last_line = content_rect.divide_y(
|
||||||
[12.0, 12.0, 24.0, 24.0, 24.0, 24.0], direction="d"
|
[12.0, 12.0, 24.0, 24.0, 24.0, 24.0], direction="d"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ def draw_footer(canvas, rect, record: ADRLine, report_date, line_no, total_lines
|
|||||||
rect.draw_border(canvas, "max_y")
|
rect.draw_border(canvas, "max_y")
|
||||||
report_date_s = [report_date.strftime("%c")]
|
report_date_s = [report_date.strftime("%c")]
|
||||||
spotting_name = [record.spot] if record.spot is not None else []
|
spotting_name = [record.spot] if record.spot is not None else []
|
||||||
pages_s = [f"Line {line_no} of {total_lines}"]
|
pages_s = ["Line %i of %i" % (line_no, total_lines)]
|
||||||
footer_s = " - ".join(report_date_s + spotting_name + pages_s)
|
footer_s = " - ".join(report_date_s + spotting_name + pages_s)
|
||||||
rect.draw_text_cell(
|
rect.draw_text_cell(
|
||||||
canvas, footer_s, font_name=font_name, font_size=10.0, inset_y=2.0
|
canvas, footer_s, font_name=font_name, font_size=10.0, inset_y=2.0
|
||||||
@@ -266,8 +266,11 @@ def create_report_for_character(
|
|||||||
records, report_date, tc_display_format: TimecodeFormat
|
records, report_date, tc_display_format: TimecodeFormat
|
||||||
):
|
):
|
||||||
|
|
||||||
outfile = f"{records[0].title}_{records[0].character_id}_{records[0].character_name}_Log.pdf"
|
outfile = "%s_%s_%s_Log.pdf" % (
|
||||||
|
records[0].title,
|
||||||
|
records[0].character_id,
|
||||||
|
records[0].character_name,
|
||||||
|
)
|
||||||
assert outfile is not None
|
assert outfile is not None
|
||||||
assert outfile[-4:] == ".pdf", "Output file must have 'pdf' extension!"
|
assert outfile[-4:] == ".pdf", "Output file must have 'pdf' extension!"
|
||||||
|
|
||||||
@@ -282,7 +285,7 @@ def create_report_for_character(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
cue_header_block, _title_header_block = header_row.split_x(4.0 * inch)
|
cue_header_block, title_header_block = header_row.split_x(4.0 * inch)
|
||||||
(cue_number_block, timecode_block), reason_block = data_row.divide_x(
|
(cue_number_block, timecode_block), reason_block = data_row.divide_x(
|
||||||
[1.5 * inch, 1.5 * inch]
|
[1.5 * inch, 1.5 * inch]
|
||||||
)
|
)
|
||||||
@@ -294,7 +297,8 @@ def create_report_for_character(
|
|||||||
)
|
)
|
||||||
|
|
||||||
c.setTitle(
|
c.setTitle(
|
||||||
f"{records[0].title} {records[0].character_name} ({records[0].character_id}) Supervisor's Log"
|
"%s %s (%s) Supervisor's Log"
|
||||||
|
% (records[0].title, records[0].character_name, records[0].character_id)
|
||||||
)
|
)
|
||||||
c.setAuthor(records[0].supervisor)
|
c.setAuthor(records[0].supervisor)
|
||||||
|
|
||||||
@@ -335,7 +339,7 @@ def create_report_for_character(
|
|||||||
def output_report(lines, tc_display_format: TimecodeFormat):
|
def output_report(lines, tc_display_format: TimecodeFormat):
|
||||||
report_date = datetime.datetime.now()
|
report_date = datetime.datetime.now()
|
||||||
events = sorted(lines, key=lambda x: x.start)
|
events = sorted(lines, key=lambda x: x.start)
|
||||||
character_numbers = {x.character_id for x in lines}
|
character_numbers = set([x.character_id for x in lines])
|
||||||
|
|
||||||
for n in character_numbers:
|
for n in character_numbers:
|
||||||
create_report_for_character(
|
create_report_for_character(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
from reportlab.lib.pagesizes import letter
|
from reportlab.lib.pagesizes import letter
|
||||||
from reportlab.lib.styles import getSampleStyleSheet
|
from reportlab.lib.styles import getSampleStyleSheet
|
||||||
@@ -12,9 +14,9 @@ from .__init__ import make_doc_template
|
|||||||
|
|
||||||
|
|
||||||
def output_report(
|
def output_report(
|
||||||
lines: list[ADRLine], tc_display_format: TimecodeFormat, font_name="Helvetica"
|
lines: List[ADRLine], tc_display_format: TimecodeFormat, font_name="Helvetica"
|
||||||
):
|
):
|
||||||
character_numbers = {n.character_id for n in lines}
|
character_numbers = set([n.character_id for n in lines])
|
||||||
# pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
# pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
||||||
|
|
||||||
for n in character_numbers:
|
for n in character_numbers:
|
||||||
@@ -25,8 +27,8 @@ def output_report(
|
|||||||
|
|
||||||
char_lines = sorted(char_lines, key=lambda line: line.start)
|
char_lines = sorted(char_lines, key=lambda line: line.start)
|
||||||
|
|
||||||
title = f"{char_lines[0].title} ({character_name}) {n} ADR Script"
|
title = "%s (%s) %s ADR Script" % (char_lines[0].title, character_name, n)
|
||||||
filename = f"{char_lines[0].title}_{n}_{character_name}_ADR Script.pdf"
|
filename = "%s_%s_%s_ADR Script.pdf" % (char_lines[0].title, n, character_name)
|
||||||
|
|
||||||
doc = make_doc_template(
|
doc = make_doc_template(
|
||||||
page_size=letter,
|
page_size=letter,
|
||||||
@@ -62,7 +64,7 @@ def output_report(
|
|||||||
finish_tc = tc_display_format.seconds_to_smpte(line.finish)
|
finish_tc = tc_display_format.seconds_to_smpte(line.finish)
|
||||||
data_block = [
|
data_block = [
|
||||||
[
|
[
|
||||||
Paragraph(line.cue_number or "[No QN]", number_style),
|
Paragraph(line.cue_number, number_style),
|
||||||
Paragraph(start_tc + " - " + finish_tc, number_style),
|
Paragraph(start_tc + " - " + finish_tc, number_style),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -78,7 +80,7 @@ def output_report(
|
|||||||
colWidths=[1.5 * inch, 6.0 * inch],
|
colWidths=[1.5 * inch, 6.0 * inch],
|
||||||
style=[("LEFTPADDING", (0, 0), (-1, -1), 0.0)],
|
style=[("LEFTPADDING", (0, 0), (-1, -1), 0.0)],
|
||||||
),
|
),
|
||||||
Paragraph(line.prompt or "[No Prompt]", prompt_style),
|
Paragraph(line.prompt, prompt_style),
|
||||||
Spacer(1.0, inch * 1.5),
|
Spacer(1.0, inch * 1.5),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ def print_advisory_tagging_error(
|
|||||||
sys.stderr.write(" ! \033[33;1mTagging error: \033[0m")
|
sys.stderr.write(" ! \033[33;1mTagging error: \033[0m")
|
||||||
ok_string = failed_string[:position]
|
ok_string = failed_string[:position]
|
||||||
not_ok_string = failed_string[position:]
|
not_ok_string = failed_string[position:]
|
||||||
sys.stderr.write(f'\033[32m"{ok_string}\033[31;1m{not_ok_string}"\033[0m\n')
|
sys.stderr.write(
|
||||||
|
f'\033[32m"{ok_string}\033[31;1m{not_ok_string}"\033[0m\n'
|
||||||
|
)
|
||||||
|
|
||||||
if parent_track_name is not None:
|
if parent_track_name is not None:
|
||||||
sys.stderr.write(f' ! > On track "{parent_track_name}"\n')
|
sys.stderr.write(f' ! > On track "{parent_track_name}"\n')
|
||||||
|
|||||||
+10
-18
@@ -1,13 +1,11 @@
|
|||||||
from __future__ import annotations
|
import datetime
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import pathlib
|
import pathlib
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from typing import List
|
||||||
from importlib.metadata import version as module_version
|
|
||||||
from xml.etree.ElementTree import TreeBuilder, tostring
|
from xml.etree.ElementTree import TreeBuilder, tostring
|
||||||
|
|
||||||
import ptulsconv
|
import ptulsconv
|
||||||
@@ -17,16 +15,13 @@ from ptulsconv.docparser.adr_entity import ADRLine
|
|||||||
|
|
||||||
|
|
||||||
def avid_marker_list(
|
def avid_marker_list(
|
||||||
lines: list[ADRLine],
|
lines: List[ADRLine],
|
||||||
report_date: datetime | None = None,
|
report_date=datetime.datetime.now(),
|
||||||
reel_start_frame=0,
|
reel_start_frame=0,
|
||||||
fps=24,
|
fps=24,
|
||||||
):
|
):
|
||||||
doc = TreeBuilder(element_factory=None)
|
doc = TreeBuilder(element_factory=None)
|
||||||
|
|
||||||
if report_date is None:
|
|
||||||
report_date = datetime.now()
|
|
||||||
|
|
||||||
doc.start("Avid:StreamItems", {"xmlns:Avid": "http://www.avid.com"})
|
doc.start("Avid:StreamItems", {"xmlns:Avid": "http://www.avid.com"})
|
||||||
doc.start("Avid:XMLFileData", {})
|
doc.start("Avid:XMLFileData", {})
|
||||||
doc.start("AvProp", {"name": "DomainMagic", "type": "string"})
|
doc.start("AvProp", {"name": "DomainMagic", "type": "string"})
|
||||||
@@ -62,8 +57,6 @@ def avid_marker_list(
|
|||||||
|
|
||||||
doc.start("List", {"id": "OMFI:ATTR:AttrRefs"})
|
doc.start("List", {"id": "OMFI:ATTR:AttrRefs"})
|
||||||
|
|
||||||
assert report_date
|
|
||||||
|
|
||||||
insert_elem(
|
insert_elem(
|
||||||
"1",
|
"1",
|
||||||
"OMFI:ATTB:IntAttribute",
|
"OMFI:ATTB:IntAttribute",
|
||||||
@@ -82,7 +75,7 @@ def avid_marker_list(
|
|||||||
line.supervisor or "",
|
line.supervisor or "",
|
||||||
)
|
)
|
||||||
|
|
||||||
marker_name = f"{line.cue_number}: {line.prompt}"
|
marker_name = "%s: %s" % (line.cue_number, line.prompt)
|
||||||
insert_elem(
|
insert_elem(
|
||||||
"2", "OMFI:ATTB:StringAttribute", "string", "_ATN_CRM_COM", marker_name
|
"2", "OMFI:ATTB:StringAttribute", "string", "_ATN_CRM_COM", marker_name
|
||||||
)
|
)
|
||||||
@@ -119,8 +112,7 @@ def dump_fmpxml(data, input_file_name, output, adr_field_map):
|
|||||||
doc.data("0")
|
doc.data("0")
|
||||||
doc.end("ERRORCODE")
|
doc.end("ERRORCODE")
|
||||||
|
|
||||||
version = module_version("ptulsconv")
|
doc.start("PRODUCT", {"NAME": ptulsconv.__name__, "VERSION": ptulsconv.__version__})
|
||||||
doc.start("PRODUCT", {"NAME": ptulsconv.__name__, "VERSION": f"{version}"})
|
|
||||||
doc.end("PRODUCT")
|
doc.end("PRODUCT")
|
||||||
|
|
||||||
doc.start(
|
doc.start(
|
||||||
@@ -155,7 +147,7 @@ def dump_fmpxml(data, input_file_name, output, adr_field_map):
|
|||||||
doc.start("COL", {})
|
doc.start("COL", {})
|
||||||
doc.start("DATA", {})
|
doc.start("DATA", {})
|
||||||
for key_attempt in field[0]:
|
for key_attempt in field[0]:
|
||||||
if key_attempt in event:
|
if key_attempt in event.keys():
|
||||||
doc.data(str(event[key_attempt]))
|
doc.data(str(event[key_attempt]))
|
||||||
break
|
break
|
||||||
doc.end("DATA")
|
doc.end("DATA")
|
||||||
@@ -178,7 +170,7 @@ def xform_options():
|
|||||||
|
|
||||||
def dump_xform_options(output=sys.stdout):
|
def dump_xform_options(output=sys.stdout):
|
||||||
print("# Available transforms:", file=output)
|
print("# Available transforms:", file=output)
|
||||||
print(f"# Transform dir: {xslt_path}", file=output)
|
print("# Transform dir: %s" % xslt_path, file=output)
|
||||||
for f in xform_options():
|
for f in xform_options():
|
||||||
base = os.path.basename(f)
|
base = os.path.basename(f)
|
||||||
name, _ = os.path.splitext(base)
|
name, _ = os.path.splitext(base)
|
||||||
@@ -196,14 +188,14 @@ def fmp_transformed_dump(data, input_file, xsl_name, output, adr_field_map):
|
|||||||
dump_fmpxml(data, input_file, pipe, adr_field_map)
|
dump_fmpxml(data, input_file, pipe, adr_field_map)
|
||||||
|
|
||||||
str_data = pipe.getvalue()
|
str_data = pipe.getvalue()
|
||||||
print_status_style(f"Base XML size {len(str_data)}")
|
print_status_style("Base XML size %i" % (len(str_data)))
|
||||||
|
|
||||||
print_status_style("Running xsltproc")
|
print_status_style("Running xsltproc")
|
||||||
|
|
||||||
xsl_path = os.path.join(
|
xsl_path = os.path.join(
|
||||||
pathlib.Path(__file__).parent.absolute(), "xslt", xsl_name + ".xsl"
|
pathlib.Path(__file__).parent.absolute(), "xslt", xsl_name + ".xsl"
|
||||||
)
|
)
|
||||||
print_status_style(f"Using xsl: {xsl_path}")
|
print_status_style("Using xsl: %s" % xsl_path)
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["xsltproc", xsl_path, "-"],
|
["xsltproc", xsl_path, "-"],
|
||||||
input=str_data,
|
input=str_data,
|
||||||
|
|||||||
Reference in New Issue
Block a user