gh-61 Add support for audio (m4a) files and accompanying tests
This commit is contained in:
parent
64695fea08
commit
58f0fadc07
|
@ -10,6 +10,7 @@ from docopt import docopt
|
||||||
from elodie import constants
|
from elodie import constants
|
||||||
from elodie import geolocation
|
from elodie import geolocation
|
||||||
from elodie.media.media import Media
|
from elodie.media.media import Media
|
||||||
|
from elodie.media.audio import Audio
|
||||||
from elodie.media.photo import Photo
|
from elodie.media.photo import Photo
|
||||||
from elodie.media.video import Video
|
from elodie.media.video import Video
|
||||||
from elodie.filesystem import FileSystem
|
from elodie.filesystem import FileSystem
|
||||||
|
@ -34,7 +35,7 @@ FILESYSTEM = FileSystem()
|
||||||
def import_file(_file, destination, album_from_folder):
|
def import_file(_file, destination, album_from_folder):
|
||||||
"""Set file metadata and move it to destination.
|
"""Set file metadata and move it to destination.
|
||||||
"""
|
"""
|
||||||
media = Media.get_class_by_file(_file, (Photo, Video))
|
media = Media.get_class_by_file(_file, [Audio, Photo, Video])
|
||||||
if not media:
|
if not media:
|
||||||
if constants.debug:
|
if constants.debug:
|
||||||
print 'Not a supported file (%s)' % _file
|
print 'Not a supported file (%s)' % _file
|
||||||
|
@ -119,7 +120,7 @@ def _update(params):
|
||||||
destination = os.path.expanduser(os.path.dirname(os.path.dirname(
|
destination = os.path.expanduser(os.path.dirname(os.path.dirname(
|
||||||
os.path.dirname(file_path))))
|
os.path.dirname(file_path))))
|
||||||
|
|
||||||
media = Media.get_class_by_file(file_path, (Photo, Video))
|
media = Media.get_class_by_file(file_path, [Audio, Photo, Video])
|
||||||
if not media:
|
if not media:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ def _update(params):
|
||||||
updated = True
|
updated = True
|
||||||
|
|
||||||
if updated:
|
if updated:
|
||||||
updated_media = Media.get_class_by_file(file_path, (Photo, Video))
|
updated_media = Media.get_class_by_file(file_path, [Audio, Photo, Video])
|
||||||
# See comments above on why we have to do this when titles
|
# See comments above on why we have to do this when titles
|
||||||
# get updated.
|
# get updated.
|
||||||
if remove_old_title_from_name and len(original_title) > 0:
|
if remove_old_title_from_name and len(original_title) > 0:
|
||||||
|
|
|
@ -92,7 +92,8 @@ def decimal_to_dms(decimal, signed=True):
|
||||||
return (
|
return (
|
||||||
pyexiv2.Rational(degrees, 1),
|
pyexiv2.Rational(degrees, 1),
|
||||||
pyexiv2.Rational(minutes, 1),
|
pyexiv2.Rational(minutes, 1),
|
||||||
pyexiv2.Rational(subseconds_fraction.numerator, subseconds_fraction.denominator) # noqa
|
pyexiv2.Rational(subseconds_fraction.numerator,
|
||||||
|
subseconds_fraction.denominator)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
"""
|
||||||
|
Author: Jaisen Mathai <jaisen@jmathai.com>
|
||||||
|
Audio package that handles all audio operations
|
||||||
|
Inherits from Video package
|
||||||
|
"""
|
||||||
|
|
||||||
|
from elodie import constants
|
||||||
|
from elodie import plist_parser
|
||||||
|
from media import Media
|
||||||
|
from video import Video
|
||||||
|
|
||||||
|
|
||||||
|
class Audio(Video):
|
||||||
|
__name__ = 'Audio'
|
||||||
|
extensions = ('m4a')
|
||||||
|
|
||||||
|
"""
|
||||||
|
@param, source, string, The fully qualified path to the audio file
|
||||||
|
"""
|
||||||
|
def __init__(self, source=None):
|
||||||
|
super(Audio, self).__init__(source)
|
|
@ -27,6 +27,7 @@ class Video(Media):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@param, source, string, The fully qualified path to the video file
|
@param, source, string, The fully qualified path to the video file
|
||||||
|
@param, Audio, class or none, The Audio class if being extendted by the Audio class
|
||||||
"""
|
"""
|
||||||
def __init__(self, source=None):
|
def __init__(self, source=None):
|
||||||
super(Video, self).__init__(source)
|
super(Video, self).__init__(source)
|
||||||
|
@ -375,7 +376,7 @@ class Video(Media):
|
||||||
|
|
||||||
# Before we do anything destructive we confirm that the
|
# Before we do anything destructive we confirm that the
|
||||||
# file is in tact.
|
# file is in tact.
|
||||||
check_media = Video(temp_movie)
|
check_media = Media.get_class_by_file(temp_movie, [self.__class__])
|
||||||
check_metadata = check_media.get_metadata()
|
check_metadata = check_media.get_metadata()
|
||||||
if(
|
if(
|
||||||
(
|
(
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,177 @@
|
||||||
|
# -*- coding: utf-8
|
||||||
|
# Project imports
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from nose.plugins.skip import SkipTest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))))
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
|
||||||
|
|
||||||
|
import helper
|
||||||
|
from elodie.media.media import Media
|
||||||
|
from elodie.media.video import Video
|
||||||
|
from elodie.media.audio import Audio
|
||||||
|
|
||||||
|
os.environ['TZ'] = 'GMT'
|
||||||
|
|
||||||
|
def test_audio_extensions():
|
||||||
|
audio = Audio()
|
||||||
|
extensions = audio.extensions
|
||||||
|
|
||||||
|
assert 'm4a' in extensions
|
||||||
|
|
||||||
|
valid_extensions = Audio.get_valid_extensions()
|
||||||
|
|
||||||
|
assert extensions == valid_extensions, valid_extensions
|
||||||
|
|
||||||
|
def test_get_coordinate():
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
coordinate = audio.get_coordinate()
|
||||||
|
|
||||||
|
assert coordinate == 29.75893888888889, coordinate
|
||||||
|
|
||||||
|
def test_get_coordinate_latitude():
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
coordinate = audio.get_coordinate('latitude')
|
||||||
|
|
||||||
|
assert coordinate == 29.75893888888889, coordinate
|
||||||
|
|
||||||
|
def test_get_coordinate_longitude():
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
coordinate = audio.get_coordinate('longitude')
|
||||||
|
|
||||||
|
assert coordinate == -95.3677, coordinate
|
||||||
|
|
||||||
|
def test_get_date_taken():
|
||||||
|
raise SkipTest('gh-32 this test fails on travisci')
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
date_taken = audio.get_date_taken()
|
||||||
|
|
||||||
|
print '%r' % date_taken
|
||||||
|
assert date_taken == (2016, 1, 4, 5, 24, 15, 0, 19, 0), date_taken
|
||||||
|
|
||||||
|
def test_get_exif():
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
exif = audio.get_exif()
|
||||||
|
|
||||||
|
assert exif is not None, exif
|
||||||
|
|
||||||
|
def test_is_valid():
|
||||||
|
audio = Audio(helper.get_file('audio.m4a'))
|
||||||
|
|
||||||
|
assert audio.is_valid()
|
||||||
|
|
||||||
|
def test_is_not_valid():
|
||||||
|
audio = Audio(helper.get_file('text.txt'))
|
||||||
|
|
||||||
|
assert not audio.is_valid()
|
||||||
|
|
||||||
|
def test_set_date_taken():
|
||||||
|
if not can_edit_exif():
|
||||||
|
raise SkipTest('avmetareadwrite executable not found')
|
||||||
|
|
||||||
|
temporary_folder, folder = helper.create_working_folder()
|
||||||
|
|
||||||
|
origin = '%s/audio.m4a' % folder
|
||||||
|
shutil.copyfile(helper.get_file('audio.m4a'), origin)
|
||||||
|
|
||||||
|
audio = Audio(origin)
|
||||||
|
status = audio.set_date_taken(datetime.datetime(2013, 9, 30, 7, 6, 5))
|
||||||
|
|
||||||
|
assert status == True, status
|
||||||
|
|
||||||
|
audio_new = Audio(origin)
|
||||||
|
metadata = audio_new.get_metadata()
|
||||||
|
|
||||||
|
date_taken = metadata['date_taken']
|
||||||
|
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
|
||||||
|
assert date_taken == (2013, 9, 30, 7, 6, 5, 0, 273, 0), metadata['date_taken']
|
||||||
|
|
||||||
|
def test_set_location():
|
||||||
|
if not can_edit_exif():
|
||||||
|
raise SkipTest('avmetareadwrite executable not found')
|
||||||
|
|
||||||
|
raise SkipTest('gh-31, precision is lost in conversion from decimal to dms')
|
||||||
|
temporary_folder, folder = helper.create_working_folder()
|
||||||
|
|
||||||
|
origin = '%s/audio.m4a' % folder
|
||||||
|
shutil.copyfile(helper.get_file('audio.m4a'), origin)
|
||||||
|
|
||||||
|
audio = Audio(origin)
|
||||||
|
origin_metadata = audio.get_metadata()
|
||||||
|
|
||||||
|
# Verify that original photo has no location information
|
||||||
|
#assert origin_metadata['latitude'] is None, origin_metadata['latitude']
|
||||||
|
#assert origin_metadata['longitude'] is None, origin_metadata['longitude']
|
||||||
|
|
||||||
|
status = audio.set_location(11.1111111111, 99.9999999999)
|
||||||
|
|
||||||
|
assert status == True, status
|
||||||
|
|
||||||
|
audio_new = Audio(origin)
|
||||||
|
metadata = audio_new.get_metadata()
|
||||||
|
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
|
||||||
|
# @TODO: understand why the decimal to degree conversion loses accuracy
|
||||||
|
assert metadata['latitude'] == 11.1111111111, metadata['latitude']
|
||||||
|
assert metadata['longitude'] == 99.9999999999, metadata['longitude']
|
||||||
|
|
||||||
|
def test_set_title():
|
||||||
|
if not can_edit_exif():
|
||||||
|
raise SkipTest('avmetareadwrite executable not found')
|
||||||
|
|
||||||
|
temporary_folder, folder = helper.create_working_folder()
|
||||||
|
|
||||||
|
origin = '%s/audio.m4a' % folder
|
||||||
|
shutil.copyfile(helper.get_file('audio.m4a'), origin)
|
||||||
|
|
||||||
|
audio = Audio(origin)
|
||||||
|
origin_metadata = audio.get_metadata()
|
||||||
|
|
||||||
|
status = audio.set_title('my audio title')
|
||||||
|
|
||||||
|
assert status == True, status
|
||||||
|
|
||||||
|
audio_new = Audio(origin)
|
||||||
|
metadata = audio_new.get_metadata()
|
||||||
|
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
|
||||||
|
assert metadata['title'] == 'my audio title', metadata['title']
|
||||||
|
|
||||||
|
def test_set_title_non_ascii():
|
||||||
|
if not can_edit_exif():
|
||||||
|
raise SkipTest('avmetareadwrite executable not found')
|
||||||
|
|
||||||
|
raise SkipTest('gh-27, non-ascii characters')
|
||||||
|
temporary_folder, folder = helper.create_working_folder()
|
||||||
|
|
||||||
|
origin = '%s/audio.m4a' % folder
|
||||||
|
shutil.copyfile(helper.get_file('audio.m4a'), origin)
|
||||||
|
|
||||||
|
audio = Audio(origin)
|
||||||
|
origin_metadata = audio.get_metadata()
|
||||||
|
|
||||||
|
status = audio.set_title('形声字 / 形聲字')
|
||||||
|
|
||||||
|
assert status == True, status
|
||||||
|
|
||||||
|
audio_new = Audio(origin)
|
||||||
|
metadata = audio_new.get_metadata()
|
||||||
|
|
||||||
|
shutil.rmtree(folder)
|
||||||
|
|
||||||
|
assert metadata['title'] == '形声字 / 形聲字', metadata['title']
|
||||||
|
|
||||||
|
def can_edit_exif():
|
||||||
|
audio = Audio()
|
||||||
|
return audio.get_avmetareadwrite()
|
Loading…
Reference in New Issue