← Back to team overview

openlp-core team mailing list archive

[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