openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #28496
[Merge] lp:~trb143/openlp/mediainfo into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/mediainfo into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~trb143/openlp/mediainfo/+merge/283692
Fix the issue of getting media length for service manager.
Add wrapper (which seems to have been decommissioned) around the MediaInfo program.
MediaInfo seems to be available for all platforms.
Cannot test on CI as we need to install mediainfo
Decide if we make MediaInfo a hard dependancy or disable the media plugin if this is not installed.
--
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/mediainfo into lp:openlp.
=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py 2015-12-31 22:46:06 +0000
+++ openlp/core/ui/media/mediacontroller.py 2016-01-22 20:19:42 +0000
@@ -33,6 +33,7 @@
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,\
parse_optical_path
+from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.common import AppLocation
from openlp.core.ui import DisplayControllerType
@@ -441,12 +442,9 @@
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False
- if not self.media_play(controller):
- critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
- translate('MediaPlugin.MediaItem', 'Unsupported File'))
- return False
- service_item.set_media_length(controller.media_info.length)
- self.media_stop(controller)
+ media_data = MediaInfoWrapper.parse(service_item.get_frame_path())
+ # duration returns in nano seconds
+ service_item.set_media_length(media_data.tracks[0].duration // 1000)
log.debug('use %s controller' % self.current_media_players[controller.controller_type])
return True
=== added file 'openlp/core/ui/media/vendor/mediainfoWrapper.py'
--- openlp/core/ui/media/vendor/mediainfoWrapper.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/media/vendor/mediainfoWrapper.py 2016-01-22 20:19:42 +0000
@@ -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())
\ No newline at end of file
=== added directory 'tests/interfaces/openlp_core_ul_media_vendor'
=== added file 'tests/interfaces/openlp_core_ul_media_vendor/__init__.py'
--- tests/interfaces/openlp_core_ul_media_vendor/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/interfaces/openlp_core_ul_media_vendor/__init__.py 2016-01-22 20:19:42 +0000
@@ -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 #
+###############################################################################
=== added file 'tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py'
--- tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py 1970-01-01 00:00:00 +0000
+++ tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py 2016-01-22 20:19:42 +0000
@@ -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])
=== added directory 'tests/resources/media'
=== added file 'tests/resources/media/avi_file.avi'
Binary files tests/resources/media/avi_file.avi 1970-01-01 00:00:00 +0000 and tests/resources/media/avi_file.avi 2016-01-22 20:19:42 +0000 differ
=== added file 'tests/resources/media/mp3_file.mp3'
Binary files tests/resources/media/mp3_file.mp3 1970-01-01 00:00:00 +0000 and tests/resources/media/mp3_file.mp3 2016-01-22 20:19:42 +0000 differ
=== added file 'tests/resources/media/mp4_file.mp4'
Binary files tests/resources/media/mp4_file.mp4 1970-01-01 00:00:00 +0000 and tests/resources/media/mp4_file.mp4 2016-01-22 20:19:42 +0000 differ
=== added file 'tests/resources/media/mpg_file.mpg'
Binary files tests/resources/media/mpg_file.mpg 1970-01-01 00:00:00 +0000 and tests/resources/media/mpg_file.mpg 2016-01-22 20:19:42 +0000 differ
Follow ups