Add wrapper for mediainfo

This commit is contained in:
Tim Bentley 2016-01-22 20:12:46 +00:00
parent 4ecd2085ed
commit 4a0330f126
8 changed files with 216 additions and 6 deletions

View File

@ -33,6 +33,7 @@ from openlp.core.lib import OpenLPToolbar, ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
parse_optical_path parse_optical_path
from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.common import AppLocation from openlp.core.common import AppLocation
from openlp.core.ui import DisplayControllerType from openlp.core.ui import DisplayControllerType
@ -441,12 +442,9 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties):
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
if not self.media_play(controller): media_data = MediaInfoWrapper.parse(service_item.get_frame_path())
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), # duration returns in nano seconds
translate('MediaPlugin.MediaItem', 'Unsupported File')) service_item.set_media_length(media_data.tracks[0].duration // 1000)
return False
service_item.set_media_length(controller.media_info.length)
self.media_stop(controller)
log.debug('use %s controller' % self.current_media_players[controller.controller_type]) log.debug('use %s controller' % self.current_media_players[controller.controller_type])
return True return True

View File

@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.ui.media.mediainfo` module contains code to run mediainfo on a media file and obtain
information related to the rwquested media.
"""
import json
import os
from subprocess import Popen
from tempfile import mkstemp
import six
from bs4 import BeautifulSoup, NavigableString
ENV_DICT = os.environ
class Track(object):
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except:
pass
return None
def __init__(self, xml_dom_fragment):
self.xml_dom_fragment = xml_dom_fragment
self.track_type = xml_dom_fragment.attrs['type']
for el in self.xml_dom_fragment.children:
if not isinstance(el, NavigableString):
node_name = el.name.lower().strip().strip('_')
if node_name == 'id':
node_name = 'track_id'
node_value = el.string
other_node_name = "other_%s" % node_name
if getattr(self, node_name) is None:
setattr(self, node_name, node_value)
else:
if getattr(self, other_node_name) is None:
setattr(self, other_node_name, [node_value, ])
else:
getattr(self, other_node_name).append(node_value)
for o in [d for d in self.__dict__.keys() if d.startswith('other_')]:
try:
primary = o.replace('other_', '')
setattr(self, primary, int(getattr(self, primary)))
except:
for v in getattr(self, o):
try:
current = getattr(self, primary)
setattr(self, primary, int(v))
getattr(self, o).append(current)
break
except:
pass
def __repr__(self):
return "<Track track_id='{0}', track_type='{1}'>".format(self.track_id, self.track_type)
def to_data(self):
data = {}
for k, v in six.iteritems(self.__dict__):
if k != 'xml_dom_fragment':
data[k] = v
return data
class MediaInfoWrapper(object):
def __init__(self, xml):
self.xml_dom = xml
xml_types = (str,) # no unicode type in python3
if isinstance(xml, xml_types):
self.xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(xml)
@staticmethod
def parse_xml_data_into_dom(xml_data):
return BeautifulSoup(xml_data, "xml")
@staticmethod
def parse(filename, environment=ENV_DICT):
command = ["mediainfo", "-f", "--Output=XML", filename]
fileno_out, fname_out = mkstemp(suffix=".xml", prefix="media-")
fileno_err, fname_err = mkstemp(suffix=".err", prefix="media-")
fp_out = os.fdopen(fileno_out, 'r+b')
fp_err = os.fdopen(fileno_err, 'r+b')
p = Popen(command, stdout=fp_out, stderr=fp_err, env=environment)
p.wait()
fp_out.seek(0)
xml_dom = MediaInfoWrapper.parse_xml_data_into_dom(fp_out.read())
fp_out.close()
fp_err.close()
os.unlink(fname_out)
os.unlink(fname_err)
return MediaInfoWrapper(xml_dom)
def _populate_tracks(self):
if self.xml_dom is None:
return
for xml_track in self.xml_dom.Mediainfo.File.find_all("track"):
self._tracks.append(Track(xml_track))
@property
def tracks(self):
if not hasattr(self, "_tracks"):
self._tracks = []
if len(self._tracks) == 0:
self._populate_tracks()
return self._tracks
def to_data(self):
data = {'tracks': []}
for track in self.tracks:
data['tracks'].append(track.to_data())
return data
def to_json(self):
return json.dumps(self.to_data())

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################

View File

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Package to test the openlp.core.ui.media package.
"""
import os
from unittest import TestCase
from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources', 'media'))
TEST_MEDIA = [['avi_file.avi', 61495], ['mp3_file.mp3', 134426], ['mpg_file.mpg', 9404], ['mp4_file.mp4', 188336]]
class TestMediainfoWrapper(TestCase):
def media_length_test(self):
"""
Test the Media Info basic functionality
"""
for test_data in TEST_MEDIA:
# GIVEN: a media file
full_path = os.path.normpath(os.path.join(TEST_PATH, test_data[0]))
# WHEN the media data is retrieved
results = MediaInfoWrapper.parse(full_path)
# THEN you can determine the run time
self.assertEqual(results.tracks[0].duration, test_data[1], 'The correct duration is returned for ' +
test_data[0])

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.