Metadata-Version: 2.4
Name: pycmx
Version: 1.4.0
Summary: Python CMX 3600 Edit Decision List Parser
License: MIT
License-File: LICENSE
Keywords: parser,film,broadcast
Author: Jamie Hardt
Author-email: jamiehardt@me.com
Requires-Python: >=3.8,<4.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Multimedia
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Text Processing
Provides-Extra: doc
Requires-Dist: sphinx (>=5.3.0) ; extra == "doc"
Requires-Dist: sphinx_rtd_theme (>=1.1.1) ; extra == "doc"
Project-URL: Documentation, https://pycmx.readthedocs.io/
Project-URL: Homepage, https://github.com/iluvcapra/pycmx
Project-URL: Repository, https://github.com/iluvcapra/pycmx.git
Project-URL: Tracker, https://github.com/iluvcapra/pycmx/issues
Description-Content-Type: text/markdown

[![Documentation Status](https://readthedocs.org/projects/pycmx/badge/?version=latest)](https://pycmx.readthedocs.io/en/latest/?badge=latest) ![](https://img.shields.io/github/license/iluvcapra/pycmx.svg) ![](https://img.shields.io/pypi/pyversions/pycmx.svg) [![](https://img.shields.io/pypi/v/pycmx.svg)](https://pypi.org/project/pycmx/) ![](https://img.shields.io/pypi/wheel/pycmx.svg)
![GitHub last commit](https://img.shields.io/github/last-commit/iluvcapra/pycmx)
[![Lint and Test](https://github.com/iluvcapra/pycmx/actions/workflows/python-package.yml/badge.svg)](https://github.com/iluvcapra/pycmx/actions/workflows/python-package.yml)


# pycmx

The `pycmx` package parses a CMX 3600 EDL and its most most common variations.

## Features

* The major variations of the CMX 3600: the standard, "File32", "File128" and
  long Adobe Premiere event numbers are automatically detected and properly
  read. Event number field and source name field sizes are determined
  dynamically for each statement for a high level of compliance at the expense
  of strictness.
* Preserves relationship between events and individual edits/clips.
* Remark or comment fields with common recognized forms are read and 
  available to the client, including clip name and source file data.
* [ASC CDL][asc] and FRMC/VFX framecount statements are parsed and
  decoded.
* Symbolically decodes transitions and audio channels.
* Does not parse or validate timecodes, does not enforce framerates, does not
  parameterize timecode or framerates in any way. This makes the parser more
  tolerant of EDLs with mixed rates.
* Unrecognized lines are accessible on the `EditList` and `Event` classes
  along with the line numbers, to help the client diagnose problems with a
  list and give the client the ability to extend the package with their own
  parsing code.

[asc]: https://en.wikipedia.org/wiki/ASC_CDL

## Usage

### Opening and Parsing EDL Files
```
>>> import pycmx
>>> with open("tests/edls/TEST.edl") as f
... 	edl = pycmx.parse_cmx3600(f)
...
>>> edl.title
'DC7 R1_v8.2'
```

### Reading Events and Edits

`EditList.events` is a generator...

```
>>> events = list( edl.events )  
>>> len(events)
120
>>> events[43].number 
'044'
```

...and events contain 1...n edits.

```
>>> events[43].edits[0].source_in 
'00:00:00:00'
>>> events[43].edits[0].transition.cut
True
>>> events[43].edits[0].record_out
'01:10:21:10'
```

### Acessing Transitions and Enabled Channels

```           
>>> events[41].edits[0].transition.dissolve
False
>>> events[41].edits[1].transition.dissolve
True
>>> events[41].edits[0].clip_name
'TC R1 V1.2 TEMP1 DX M.WAV'
>>> events[41].edits[1].clip_name
'TC R1 V6 TEMP2 M DX.WAV'
   
              # parsed channel maps are also
              # available to the client
>>> events[2].edits[0].channels.get_audio_channel(7)
True
>>> events[2].edits[0].channels.get_audio_channel(6)
False
>>> for c in events[2].edits[0].channels.channels:
...     print(f"Audio channel {c} is present")
... 
Audio channel 7 is present
>>> events[2].edits[0].channels.video
False
```

