Module subsync.synchro.output
Expand source code
from subsync import utils
from subsync.translations import _
from subsync.error import Error
import os
import logging
logger = logging.getLogger(__name__)
__pdoc__ = {
'PathFormatter': False,
'ConditionalFormatter': False,
}
class OutputFile(object):
"""Subtitle target description - specifies where output should be saved."""
def __init__(self, path=None, *, enc=None, fps=None):
"""
Parameters
----------
path: str
Output path or pattern. Path could be literal or may contain
following variables:
- `{sub_path}`/`{ref_path}` - subtitle/reference full path;
- `{sub_no}`/`{ref_no}` - stream number;
- `{sub_lang}`/`{ref_lang}` - 3-letter language code;
- `{sub_name}`/`{ref_name}` - file name (without path and extension);
- `{sub_dir}`/`{ref_dir}` - directory path;
- `{if:<field>:<value>}` - if field is set, append value;
- `{if_not:<field>:<value>}` - if field is not set, append value.
enc: str, optional
Character encoding, default is 'UTF-8'.
fps: float, optional
Framerate, applies only for frame-based subtitles.
Notes
-----
Subtitle format is derived from file extension, thus path must end with
one of the supported extensions.
Examples
--------
`{ref_dir}/{ref_name}{if:sub_lang:.}{sub_lang}.srt`
`{sub_dir}/{sub_name}-out.ssa`
"""
self.path = path
self.enc = enc or 'UTF-8'
self.fps = fps
self.pathFormatter = None
def getPath(self, sub, ref):
"""Compile path pattern for given `sub` and `ref`."""
if self.pathFormatter is None:
self.pathFormatter = PathFormatter()
return self.pathFormatter.format(self.path, sub, ref)
def validateOutputPattern(self):
"""Raise exception for invalid path pattern."""
validatePattern(self.path)
def serialize(self):
res = {}
if self.path: res['path'] = self.path
if self.enc: res['enc'] = self.enc
if self.fps: res['fps'] = self.fps
return res
def __repr__(self):
return utils.fmtobj(self.__class__.__name__,
path = self.path,
enc = self.enc,
fps = self.fps)
def __str__(self):
return utils.fmtstr(self.path,
enc = self.enc,
fps = self.fps)
class PathFormatter(object):
def __init__(self):
self.clearCache()
def clearCache(self):
self.d = {}
self.cache = (None, None, None)
def format(self, pattern, sub, ref):
if pattern is None or sub is None or ref is None:
return None
cacheKey = (sub.path, sub.no, sub.lang, ref.path, ref.no, ref.lang)
if self.cache[0] == cacheKey:
if self.cache[1] == pattern:
return self.cache[2]
else:
self.d = {}
for prefix, item in [ ('sub_', sub), ('ref_', ref) ]:
self.d[ prefix + 'path' ] = item.path
self.d[ prefix + 'no' ] = str(item.no + 1)
self.d[ prefix + 'lang' ] = item.lang or ''
self.d[ prefix + 'name' ] = os.path.splitext(os.path.basename(item.path))[0]
self.d[ prefix + 'dir' ] = os.path.dirname(item.path)
path = _formatPattern(pattern, self.d)
self.cache = (cacheKey, pattern, path)
return path
def validatePattern(pattern):
"""Raise exception for invalid path pattern."""
d = {}
for prefix in [ 'sub_', 'ref_' ]:
for name in [ 'path', 'no', 'lang', 'name', 'dir' ]:
d[ prefix + name ] = ''
_formatPattern(pattern, d)
def _formatPattern(pattern, formatter):
try:
return pattern.format(**formatter, **{
'if': ConditionalFormatter(formatter),
'if_not': ConditionalFormatter(formatter, inverted=True)
})
except KeyError as e:
raise Error(_('Invalid output pattern, invalid keyword: {}').format(e),
pattern=pattern)
except Exception as e:
raise Error(_('Invalid output pattern, {}').format(e), pattern=pattern)
class ConditionalFormatter(object):
def __init__(self, items, inverted=False):
self.items = items
self.inverted = inverted
def __format__(self, fmt):
key, val = fmt.split(':', 1)
if bool(self.items[key]) ^ self.inverted:
return val
else:
return ''
Functions
def validatePattern(pattern)
-
Raise exception for invalid path pattern.
Expand source code
def validatePattern(pattern): """Raise exception for invalid path pattern.""" d = {} for prefix in [ 'sub_', 'ref_' ]: for name in [ 'path', 'no', 'lang', 'name', 'dir' ]: d[ prefix + name ] = '' _formatPattern(pattern, d)
Classes
class OutputFile (path=None, *, enc=None, fps=None)
-
Subtitle target description - specifies where output should be saved.
Parameters
path
:str
-
Output path or pattern. Path could be literal or may contain following variables:
{sub_path}
/{ref_path}
- subtitle/reference full path;{sub_no}
/{ref_no}
- stream number;{sub_lang}
/{ref_lang}
- 3-letter language code;{sub_name}
/{ref_name}
- file name (without path and extension);{sub_dir}
/{ref_dir}
- directory path;{if:<field>:<value>}
- if field is set, append value;{if_not:<field>:<value>}
- if field is not set, append value.
enc
:str
, optional- Character encoding, default is 'UTF-8'.
fps
:float
, optional- Framerate, applies only for frame-based subtitles.
Notes
Subtitle format is derived from file extension, thus path must end with one of the supported extensions.
Examples
{ref_dir}/{ref_name}{if:sub_lang:.}{sub_lang}.srt
{sub_dir}/{sub_name}-out.ssa
Expand source code
class OutputFile(object): """Subtitle target description - specifies where output should be saved.""" def __init__(self, path=None, *, enc=None, fps=None): """ Parameters ---------- path: str Output path or pattern. Path could be literal or may contain following variables: - `{sub_path}`/`{ref_path}` - subtitle/reference full path; - `{sub_no}`/`{ref_no}` - stream number; - `{sub_lang}`/`{ref_lang}` - 3-letter language code; - `{sub_name}`/`{ref_name}` - file name (without path and extension); - `{sub_dir}`/`{ref_dir}` - directory path; - `{if:<field>:<value>}` - if field is set, append value; - `{if_not:<field>:<value>}` - if field is not set, append value. enc: str, optional Character encoding, default is 'UTF-8'. fps: float, optional Framerate, applies only for frame-based subtitles. Notes ----- Subtitle format is derived from file extension, thus path must end with one of the supported extensions. Examples -------- `{ref_dir}/{ref_name}{if:sub_lang:.}{sub_lang}.srt` `{sub_dir}/{sub_name}-out.ssa` """ self.path = path self.enc = enc or 'UTF-8' self.fps = fps self.pathFormatter = None def getPath(self, sub, ref): """Compile path pattern for given `sub` and `ref`.""" if self.pathFormatter is None: self.pathFormatter = PathFormatter() return self.pathFormatter.format(self.path, sub, ref) def validateOutputPattern(self): """Raise exception for invalid path pattern.""" validatePattern(self.path) def serialize(self): res = {} if self.path: res['path'] = self.path if self.enc: res['enc'] = self.enc if self.fps: res['fps'] = self.fps return res def __repr__(self): return utils.fmtobj(self.__class__.__name__, path = self.path, enc = self.enc, fps = self.fps) def __str__(self): return utils.fmtstr(self.path, enc = self.enc, fps = self.fps)
Methods
def getPath(self, sub, ref)
-
Compile path pattern for given
sub
andref
.Expand source code
def getPath(self, sub, ref): """Compile path pattern for given `sub` and `ref`.""" if self.pathFormatter is None: self.pathFormatter = PathFormatter() return self.pathFormatter.format(self.path, sub, ref)
def serialize(self)
-
Expand source code
def serialize(self): res = {} if self.path: res['path'] = self.path if self.enc: res['enc'] = self.enc if self.fps: res['fps'] = self.fps return res
def validateOutputPattern(self)
-
Raise exception for invalid path pattern.
Expand source code
def validateOutputPattern(self): """Raise exception for invalid path pattern.""" validatePattern(self.path)