mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2025-12-31 17:00:41 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3365c113d | ||
|
|
fbf4d72915 | ||
|
|
90f273cf99 | ||
|
|
bec3d98ee7 | ||
|
|
a87bc71755 | ||
|
|
4817e7eb49 | ||
|
|
07832f7133 | ||
|
|
f3d03296d5 | ||
|
|
9496912b15 | ||
|
|
1077b49ce0 | ||
|
|
90042d57b2 | ||
|
|
f12d7dfea0 | ||
|
|
c2327568a8 | ||
|
|
722df48f9b | ||
|
|
17c0357364 | ||
|
|
7e88c46d54 | ||
|
|
df90c67a73 | ||
|
|
cc107bf65d | ||
|
|
f9c68e0995 | ||
|
|
a98dd2668a | ||
|
|
d8ff4ed63b | ||
|
|
084c3d7ae5 | ||
|
|
e69b71e989 | ||
|
|
6fe6126f3a | ||
|
|
e57c76a722 | ||
|
|
e40a2c5471 | ||
|
|
dec6180744 |
4
.github/workflows/pythonpublish.yml
vendored
4
.github/workflows/pythonpublish.yml
vendored
@@ -2,7 +2,7 @@ name: Upload Python Package
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [published]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Build and publish
|
- name: Build and publish
|
||||||
env:
|
env:
|
||||||
TWINE_USERNAME: __token__
|
TWINE_USERNAME: __token__
|
||||||
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
TWINE_PASSWORD: ${{ secrets.PYPI_APIKEY }}
|
||||||
run: |
|
run: |
|
||||||
python setup.py sdist bdist_wheel
|
python setup.py sdist bdist_wheel
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|||||||
29
.readthedocs.yaml
Normal file
29
.readthedocs.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# .readthedocs.yaml
|
||||||
|
# Read the Docs configuration file
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the version of Python and other tools you might need
|
||||||
|
build:
|
||||||
|
os: ubuntu-20.04
|
||||||
|
tools:
|
||||||
|
python: "3.10"
|
||||||
|
# You can also specify other tool versions:
|
||||||
|
# nodejs: "16"
|
||||||
|
# rust: "1.55"
|
||||||
|
# golang: "1.17"
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/source/conf.py
|
||||||
|
|
||||||
|
#If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
|
||||||
|
#Optionally declare the Python requirements required to build your docs
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: requirements.txt
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
[](https://wavinfo.readthedocs.io/en/latest/?badge=latest)   [](https://pypi.org/project/wavinfo/) 
|
[](https://wavinfo.readthedocs.io/en/latest/?badge=latest)   [](https://pypi.org/project/wavinfo/) 
|
||||||

|

|
||||||
|
|
||||||
<!--  -->
|
|
||||||
|
|
||||||
# wavinfo
|
# wavinfo
|
||||||
|
|
||||||
The `wavinfo` package allows you to probe WAVE and [RF64/WAVE files][eburf64] and extract extended metadata, with an emphasis on film, video and professional music production metadata.
|
The `wavinfo` package allows you to probe WAVE and [RF64/WAVE files][eburf64] and extract extended metadata, with an emphasis on film, video and professional music production metadata.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line.
|
||||||
SPHINXOPTS =
|
SPHINXOPTS =
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD = sphinx-build
|
||||||
SOURCEDIR = .
|
SOURCEDIR = source
|
||||||
BUILDDIR = _build
|
BUILDDIR = _build
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
# Put it first so that "make" without argument is like "make help".
|
||||||
@@ -16,4 +16,4 @@ help:
|
|||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
%: Makefile
|
%: Makefile
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
|
|
||||||
pushd %~dp0
|
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
|
||||||
set SPHINXBUILD=sphinx-build
|
|
||||||
)
|
|
||||||
set SOURCEDIR=.
|
|
||||||
set BUILDDIR=_build
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
|
||||||
|
|
||||||
%SPHINXBUILD% >NUL 2>NUL
|
|
||||||
if errorlevel 9009 (
|
|
||||||
echo.
|
|
||||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
||||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
||||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
||||||
echo.may add the Sphinx directory to PATH.
|
|
||||||
echo.
|
|
||||||
echo.If you don't have Sphinx installed, grab it from
|
|
||||||
echo.http://sphinx-doc.org/
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:help
|
|
||||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
popd
|
|
||||||
18
docs/source/classes.rst
Normal file
18
docs/source/classes.rst
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Other wavinfo Classes
|
||||||
|
===============
|
||||||
|
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_reader.WavInfoReader
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. automethod:: __init__
|
||||||
|
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_reader.WavAudioFormat
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_reader.WavDataDescriptor
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -14,19 +14,21 @@
|
|||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
sys.path.insert(0, os.path.abspath('../..'))
|
||||||
|
sys.path.insert(0, os.path.abspath("../../.."))
|
||||||
|
print(sys.path)
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = u'wavinfo'
|
project = u'wavinfo'
|
||||||
copyright = u'2019, Jamie Hardt'
|
copyright = u'2022, Jamie Hardt'
|
||||||
author = u'Jamie Hardt'
|
author = u'Jamie Hardt'
|
||||||
|
|
||||||
# The short X.Y version
|
# The short X.Y version
|
||||||
version = u''
|
version = u''
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = u'v1.1'
|
release = u'v1.7.1'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
@@ -61,7 +63,7 @@ master_doc = 'index'
|
|||||||
#
|
#
|
||||||
# This is also used if you do content translation via gettext catalogs.
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
# Usually you set "language" from the command line for these cases.
|
# Usually you set "language" from the command line for these cases.
|
||||||
language = None
|
language = 'en'
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
@@ -6,30 +6,15 @@
|
|||||||
Welcome to wavinfo's documentation!
|
Welcome to wavinfo's documentation!
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
|
|
||||||
.. module:: wavinfo
|
|
||||||
|
|
||||||
.. autoclass:: WavInfoReader
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. automethod:: __init__
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: wavinfo.wave_reader.WavAudioFormat
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: wavinfo.wave_reader.WavDataDescriptor
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: Notes:
|
:caption: Notes:
|
||||||
|
|
||||||
metadata_scopes/bext.rst
|
metadata_scopes/bext.rst
|
||||||
metadata_scopes/ixml.rst
|
metadata_scopes/ixml.rst
|
||||||
metadata_scopes/info.rst
|
metadata_scopes/info.rst
|
||||||
|
|
||||||
|
classes
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
Broadcast WAV Extension
|
Broadcast WAV Extension
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
.. module:: wavinfo
|
|
||||||
|
|
||||||
.. autoclass:: wavinfo.wave_bext_reader.WavBextReader
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
@@ -63,3 +58,14 @@ Result:
|
|||||||
Originator Time: 12:40:00
|
Originator Time: 12:40:00
|
||||||
Time Reference: 2190940753
|
Time Reference: 2190940753
|
||||||
A=PCM,F=48000,W=24,M=stereo,R=48000,T=2 Ch
|
A=PCM,F=48000,W=24,M=stereo,R=48000,T=2 Ch
|
||||||
|
|
||||||
|
|
||||||
|
Class Reference
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. module:: wavinfo
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_bext_reader.WavBextReader
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
INFO Metadata
|
INFO Metadata
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
||||||
.. module:: wavinfo
|
|
||||||
|
|
||||||
.. autoclass:: wavinfo.wave_info_reader.WavInfoChunkReader
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -28,5 +20,14 @@ music library software.
|
|||||||
print("INFO Comment:", bullet.info.comment)
|
print("INFO Comment:", bullet.info.comment)
|
||||||
|
|
||||||
|
|
||||||
|
Class Reference
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. module:: wavinfo
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_info_reader.WavInfoChunkReader
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
iXML Production Recorder Metadata
|
iXML Production Recorder Metadata
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
|
|
||||||
.. module:: wavinfo
|
|
||||||
|
|
||||||
.. autoclass:: wavinfo.wave_ixml_reader.WavIXMLFormat
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
iXML allows an XML document to be embedded in a WAV file.
|
iXML allows an XML document to be embedded in a WAV file.
|
||||||
@@ -41,4 +34,12 @@ Result:
|
|||||||
iXML File Family UID: USSDVGR1112089007124001008206300
|
iXML File Family UID: USSDVGR1112089007124001008206300
|
||||||
|
|
||||||
|
|
||||||
|
Class Reference
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. module:: wavinfo
|
||||||
|
|
||||||
|
.. autoclass:: wavinfo.wave_ixml_reader.WavIXMLFormat
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Wavinfo
|
Wavinfo
|
||||||
"""
|
"""
|
||||||
__version__ = '1.7.0'
|
__version__ = '1.7.1'
|
||||||
__author__ = 'Jamie Hardt <jamiehardt@gmail.com>'
|
__author__ = 'Jamie Hardt <jamiehardt@gmail.com>'
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from typing import Union
|
|
||||||
import binascii
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +11,7 @@ class UMIDParser:
|
|||||||
|
|
||||||
This implementation is based on SMPTE ST 330:2011
|
This implementation is based on SMPTE ST 330:2011
|
||||||
"""
|
"""
|
||||||
def __init__(self, raw_umid: bytearray):
|
def __init__(self, raw_umid: bytes):
|
||||||
self.raw_umid = raw_umid
|
self.raw_umid = raw_umid
|
||||||
#
|
#
|
||||||
# @property
|
# @property
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import struct
|
import struct
|
||||||
import binascii
|
|
||||||
from .umid_parser import UMIDParser
|
from .umid_parser import UMIDParser
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
class WavBextReader:
|
class WavBextReader:
|
||||||
def __init__(self, bext_data, encoding):
|
def __init__(self, bext_data, encoding):
|
||||||
@@ -16,44 +16,44 @@ class WavBextReader:
|
|||||||
rest_starts = struct.calcsize(packstring)
|
rest_starts = struct.calcsize(packstring)
|
||||||
unpacked = struct.unpack(packstring, bext_data[:rest_starts])
|
unpacked = struct.unpack(packstring, bext_data[:rest_starts])
|
||||||
|
|
||||||
def sanitize_bytes(b):
|
def sanitize_bytes(b : bytes) -> str:
|
||||||
first_null = next((index for index, byte in enumerate(b) if byte == 0), None)
|
first_null = next((index for index, byte in enumerate(b) if byte == 0), None)
|
||||||
trimmed = b if first_null is None else b[:first_null]
|
trimmed = b if first_null is None else b[:first_null]
|
||||||
decoded = trimmed.decode(encoding)
|
decoded = trimmed.decode(encoding)
|
||||||
return decoded
|
return decoded
|
||||||
|
|
||||||
#: Description. A free-text field up to 256 characters long.
|
#: Description. A free-text field up to 256 characters long.
|
||||||
self.description = sanitize_bytes(unpacked[0])
|
self.description : str = sanitize_bytes(unpacked[0])
|
||||||
#: Originator. Usually the name of the encoding application, sometimes
|
#: Originator. Usually the name of the encoding application, sometimes
|
||||||
#: a artist name.
|
#: a artist name.
|
||||||
self.originator = sanitize_bytes(unpacked[1])
|
self.originator : str = sanitize_bytes(unpacked[1])
|
||||||
#: A unique identifier for the file, a serial number.
|
#: A unique identifier for the file, a serial number.
|
||||||
self.originator_ref = sanitize_bytes(unpacked[2])
|
self.originator_ref : str = sanitize_bytes(unpacked[2])
|
||||||
#: Date of the recording, in the format YYY-MM-DD
|
#: Date of the recording, in the format YYY-MM-DD
|
||||||
self.originator_date = sanitize_bytes(unpacked[3])
|
self.originator_date : str = sanitize_bytes(unpacked[3])
|
||||||
#: Time of the recording, in the format HH:MM:SS.
|
#: Time of the recording, in the format HH:MM:SS.
|
||||||
self.originator_time = sanitize_bytes(unpacked[4])
|
self.originator_time : str = sanitize_bytes(unpacked[4])
|
||||||
#: The sample offset of the start of the file relative to an
|
#: The sample offset of the start of the file relative to an
|
||||||
#: epoch, usually midnight the day of the recording.
|
#: epoch, usually midnight the day of the recording.
|
||||||
self.time_reference = unpacked[5]
|
self.time_reference : int = unpacked[5]
|
||||||
#: A variable-length text field containing a list of processes and
|
#: A variable-length text field containing a list of processes and
|
||||||
#: and conversions performed on the file.
|
#: and conversions performed on the file.
|
||||||
self.coding_history = sanitize_bytes(bext_data[rest_starts:])
|
self.coding_history : str = sanitize_bytes(bext_data[rest_starts:])
|
||||||
#: BEXT version.
|
#: BEXT version.
|
||||||
self.version = unpacked[6]
|
self.version : int = unpacked[6]
|
||||||
#: SMPTE 330M UMID of this audio file, 64 bytes are allocated though the UMID
|
#: SMPTE 330M UMID of this audio file, 64 bytes are allocated though the UMID
|
||||||
#: may only be 32 bytes long.
|
#: may only be 32 bytes long.
|
||||||
self.umid = None
|
self.umid : Optional[bytes] = None
|
||||||
#: EBU R128 Integrated loudness, in LUFS.
|
#: EBU R128 Integrated loudness, in LUFS.
|
||||||
self.loudness_value = None
|
self.loudness_value : Optional[float] = None
|
||||||
#: EBU R128 Loudness rante, in LUFS.
|
#: EBU R128 Loudness rante, in LUFS.
|
||||||
self.loudness_range = None
|
self.loudness_range : Optional[float] = None
|
||||||
#: True peak level, in dBFS TP
|
#: True peak level, in dBFS TP
|
||||||
self.max_true_peak = None
|
self.max_true_peak : Optional[float] = None
|
||||||
#: EBU R128 Maximum momentary loudness, in LUFS
|
#: EBU R128 Maximum momentary loudness, in LUFS
|
||||||
self.max_momentary_loudness = None
|
self.max_momentary_loudness : Optional[float] = None
|
||||||
#: EBU R128 Maximum short-term loudness, in LUFS.
|
#: EBU R128 Maximum short-term loudness, in LUFS.
|
||||||
self.max_shortterm_loudness = None
|
self.max_shortterm_loudness : Optional[float] = None
|
||||||
|
|
||||||
if self.version > 0:
|
if self.version > 0:
|
||||||
self.umid = unpacked[7]
|
self.umid = unpacked[7]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from .riff_parser import parse_chunk, ListChunkDescriptor
|
from .riff_parser import parse_chunk, ListChunkDescriptor
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
class WavInfoChunkReader:
|
class WavInfoChunkReader:
|
||||||
|
|
||||||
@@ -14,40 +15,40 @@ class WavInfoChunkReader:
|
|||||||
self.info_chunk = next((chunk for chunk in list_chunks if chunk.signature == b'INFO'), None)
|
self.info_chunk = next((chunk for chunk in list_chunks if chunk.signature == b'INFO'), None)
|
||||||
|
|
||||||
#: 'ICOP' Copyright
|
#: 'ICOP' Copyright
|
||||||
self.copyright = self._get_field(f, b'ICOP')
|
self.copyright : Optional[str] = self._get_field(f, b'ICOP')
|
||||||
#: 'IPRD' Product
|
#: 'IPRD' Product
|
||||||
self.product = self._get_field(f, b'IPRD')
|
self.product : Optional[str]= self._get_field(f, b'IPRD')
|
||||||
self.album = self.product
|
self.album : Optional[str] = self.product
|
||||||
#: 'IGNR' Genre
|
#: 'IGNR' Genre
|
||||||
self.genre = self._get_field(f, b'IGNR')
|
self.genre : Optional[str] = self._get_field(f, b'IGNR')
|
||||||
#: 'ISBJ' Supject
|
#: 'ISBJ' Supject
|
||||||
self.subject = self._get_field(f, b'ISBJ')
|
self.subject : Optional[str] = self._get_field(f, b'ISBJ')
|
||||||
#: 'IART' Artist, composer, author
|
#: 'IART' Artist, composer, author
|
||||||
self.artist = self._get_field(f, b'IART')
|
self.artist : Optional[str] = self._get_field(f, b'IART')
|
||||||
#: 'ICMT' Comment
|
#: 'ICMT' Comment
|
||||||
self.comment = self._get_field(f, b'ICMT')
|
self.comment : Optional[str] = self._get_field(f, b'ICMT')
|
||||||
#: 'ISFT' Software, encoding application
|
#: 'ISFT' Software, encoding application
|
||||||
self.software = self._get_field(f, b'ISFT')
|
self.software : Optional[str] = self._get_field(f, b'ISFT')
|
||||||
#: 'ICRD' Created date
|
#: 'ICRD' Created date
|
||||||
self.created_date = self._get_field(f, b'ICRD')
|
self.created_date : Optional[str] = self._get_field(f, b'ICRD')
|
||||||
#: 'IENG' Engineer
|
#: 'IENG' Engineer
|
||||||
self.engineer = self._get_field(f, b'IENG')
|
self.engineer : Optional[str] = self._get_field(f, b'IENG')
|
||||||
#: 'ITCH' Technician
|
#: 'ITCH' Technician
|
||||||
self.technician = self._get_field(f, b'ITCH')
|
self.technician : Optional[str] = self._get_field(f, b'ITCH')
|
||||||
#: 'IKEY' Keywords, keyword list
|
#: 'IKEY' Keywords, keyword list
|
||||||
self.keywords = self._get_field(f, b'IKEY')
|
self.keywords : Optional[str] = self._get_field(f, b'IKEY')
|
||||||
#: 'INAM' Name, title
|
#: 'INAM' Name, title
|
||||||
self.title = self._get_field(f, b'INAM')
|
self.title : Optional[str] = self._get_field(f, b'INAM')
|
||||||
#: 'ISRC' Source
|
#: 'ISRC' Source
|
||||||
self.source = self._get_field(f, b'ISRC')
|
self.source : Optional[str] = self._get_field(f, b'ISRC')
|
||||||
#: 'TAPE' Tape
|
#: 'TAPE' Tape
|
||||||
self.tape = self._get_field(f, b'TAPE')
|
self.tape : Optional[str] = self._get_field(f, b'TAPE')
|
||||||
#: 'IARL' Archival Location
|
#: 'IARL' Archival Location
|
||||||
self.archival_location = self._get_field(f, b'IARL')
|
self.archival_location : Optional[str] = self._get_field(f, b'IARL')
|
||||||
#: 'ICSM' Commissioned
|
#: 'ICSM' Commissioned
|
||||||
self.commissioned = self._get_field(f, b'ICMS')
|
self.commissioned : Optional[str] = self._get_field(f, b'ICMS')
|
||||||
|
|
||||||
def _get_field(self, f, field_ident):
|
def _get_field(self, f, field_ident) -> Optional[str]:
|
||||||
search = next(((chunk.start, chunk.length) for chunk in self.info_chunk.children if chunk.ident == field_ident),
|
search = next(((chunk.start, chunk.length) for chunk in self.info_chunk.children if chunk.ident == field_ident),
|
||||||
None)
|
None)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
import io
|
import io
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
IXMLTrack = namedtuple('IXMLTrack', ['channel_index', 'interleave_index', 'name', 'function'])
|
IXMLTrack = namedtuple('IXMLTrack', ['channel_index', 'interleave_index', 'name', 'function'])
|
||||||
|
|
||||||
@@ -20,10 +20,12 @@ class WavIXMLFormat:
|
|||||||
parser = ET.XMLParser(recover=True)
|
parser = ET.XMLParser(recover=True)
|
||||||
self.parsed = ET.parse(xml_bytes, parser=parser)
|
self.parsed = ET.parse(xml_bytes, parser=parser)
|
||||||
|
|
||||||
def _get_text_value(self, xpath):
|
def _get_text_value(self, xpath) -> Optional[str]:
|
||||||
e = self.parsed.find("./" + xpath)
|
e = self.parsed.find("./" + xpath)
|
||||||
if e is not None:
|
if e is not None:
|
||||||
return e.text
|
return e.text
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def raw_xml(self):
|
def raw_xml(self):
|
||||||
@@ -46,35 +48,35 @@ class WavIXMLFormat:
|
|||||||
function=track.xpath('string(FUNCTION/text())'))
|
function=track.xpath('string(FUNCTION/text())'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def project(self):
|
def project(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
The project/film name entered for the recording.
|
The project/film name entered for the recording.
|
||||||
"""
|
"""
|
||||||
return self._get_text_value("PROJECT")
|
return self._get_text_value("PROJECT")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scene(self):
|
def scene(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Scene/slate.
|
Scene/slate.
|
||||||
"""
|
"""
|
||||||
return self._get_text_value("SCENE")
|
return self._get_text_value("SCENE")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def take(self):
|
def take(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Take number.
|
Take number.
|
||||||
"""
|
"""
|
||||||
return self._get_text_value("TAKE")
|
return self._get_text_value("TAKE")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tape(self):
|
def tape(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Tape name.
|
Tape name.
|
||||||
"""
|
"""
|
||||||
return self._get_text_value("TAPE")
|
return self._get_text_value("TAPE")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def family_uid(self):
|
def family_uid(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
The globally-unique ID for this file family. This may be in the format
|
The globally-unique ID for this file family. This may be in the format
|
||||||
of a GUID, or an EBU Rec 9 source identifier, or some other dumb number.
|
of a GUID, or an EBU Rec 9 source identifier, or some other dumb number.
|
||||||
@@ -82,7 +84,7 @@ class WavIXMLFormat:
|
|||||||
return self._get_text_value("FILE_SET/FAMILY_UID")
|
return self._get_text_value("FILE_SET/FAMILY_UID")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def family_name(self):
|
def family_name(self) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
The name of this file's file family.
|
The name of this file's file family.
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user