bazarr/libs/knowit/providers/enzyme.py

154 lines
6.3 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import json
import logging
from collections import defaultdict
from logging import NullHandler, getLogger
import enzyme
from .. import OrderedDict
from ..properties import (
AudioCodec,
Basic,
Duration,
Language,
Quantity,
VideoCodec,
YesNo,
)
from ..property import Property
from ..provider import (
MalformedFileError,
Provider,
)
from ..rules import (
AudioChannelsRule,
ClosedCaptionRule,
HearingImpairedRule,
LanguageRule,
ResolutionRule,
)
from ..serializer import get_json_encoder
from ..units import units
from ..utils import todict
logger = getLogger(__name__)
logger.addHandler(NullHandler())
class EnzymeProvider(Provider):
"""Enzyme Provider."""
def __init__(self, config, *args, **kwargs):
"""Init method."""
super(EnzymeProvider, self).__init__(config, {
'general': OrderedDict([
('title', Property('title', description='media title')),
('duration', Duration('duration', description='media duration')),
]),
'video': OrderedDict([
('id', Basic('number', int, description='video track number')),
('name', Property('name', description='video track name')),
('language', Language('language', description='video language')),
('width', Quantity('width', units.pixel)),
('height', Quantity('height', units.pixel)),
('scan_type', YesNo('interlaced', yes='Interlaced', no='Progressive', default='Progressive',
description='video scan type')),
('resolution', None), # populated with ResolutionRule
# ('bit_depth', Property('bit_depth', Integer('video bit depth'))),
('codec', VideoCodec(config, 'codec_id', description='video codec')),
('forced', YesNo('forced', hide_value=False, description='video track forced')),
('default', YesNo('default', hide_value=False, description='video track default')),
('enabled', YesNo('enabled', hide_value=True, description='video track enabled')),
]),
'audio': OrderedDict([
('id', Basic('number', int, description='audio track number')),
('name', Property('name', description='audio track name')),
('language', Language('language', description='audio language')),
('codec', AudioCodec(config, 'codec_id', description='audio codec')),
('channels_count', Basic('channels', int, description='audio channels count')),
('channels', None), # populated with AudioChannelsRule
('forced', YesNo('forced', hide_value=False, description='audio track forced')),
('default', YesNo('default', hide_value=False, description='audio track default')),
('enabled', YesNo('enabled', hide_value=True, description='audio track enabled')),
]),
'subtitle': OrderedDict([
('id', Basic('number', int, description='subtitle track number')),
('name', Property('name', description='subtitle track name')),
('language', Language('language', description='subtitle language')),
('hearing_impaired', None), # populated with HearingImpairedRule
('closed_caption', None), # populated with ClosedCaptionRule
('forced', YesNo('forced', hide_value=False, description='subtitle track forced')),
('default', YesNo('default', hide_value=False, description='subtitle track default')),
('enabled', YesNo('enabled', hide_value=True, description='subtitle track enabled')),
]),
}, {
'video': OrderedDict([
('language', LanguageRule('video language')),
('resolution', ResolutionRule('video resolution')),
]),
'audio': OrderedDict([
('language', LanguageRule('audio language')),
('channels', AudioChannelsRule('audio channels')),
]),
'subtitle': OrderedDict([
('language', LanguageRule('subtitle language')),
('hearing_impaired', HearingImpairedRule('subtitle hearing impaired')),
('closed_caption', ClosedCaptionRule('closed caption')),
])
})
def accepts(self, video_path):
"""Accept only MKV files."""
return video_path.lower().endswith('.mkv')
@classmethod
def extract_info(cls, video_path):
"""Extract info from the video."""
with open(video_path, 'rb') as f:
return todict(enzyme.MKV(f))
def describe(self, video_path, context):
"""Return video metadata."""
try:
data = defaultdict(dict)
ff = self.extract_info(video_path)
def debug_data():
"""Debug data."""
return json.dumps(ff, cls=get_json_encoder(context), indent=4, ensure_ascii=False)
context['debug_data'] = debug_data
if logger.isEnabledFor(logging.DEBUG):
logger.debug('Video %r scanned using enzyme %r has raw data:\n%s',
video_path, enzyme.__version__, debug_data)
data.update(ff)
if 'info' in data and data['info'] is None:
return {}
except enzyme.MalformedMKVError: # pragma: no cover
raise MalformedFileError
if logger.level == logging.DEBUG:
logger.debug('Video {video_path} scanned using Enzyme {version} has raw data:\n{data}',
video_path=video_path, version=enzyme.__version__, data=json.dumps(data))
result = self._describe_tracks(video_path, data.get('info', {}), data.get('video_tracks'),
data.get('audio_tracks'), data.get('subtitle_tracks'), context)
if not result:
raise MalformedFileError
result['provider'] = {
'name': 'enzyme',
'version': self.version
}
return result
@property
def version(self):
"""Return enzyme version information."""
return {'enzyme': enzyme.__version__}