elodie.media.video.Video.get_date_taken()   C
last analyzed

Complexity

Conditions 11

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 33
nop 1
dl 0
loc 47
rs 5.4
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like elodie.media.video.Video.get_date_taken() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
The video module contains the :class:`Video` class, which represents video
3
objects (AVI, MOV, etc.).
4
5
.. moduleauthor:: Jaisen Mathai <[email protected]>
6
"""
7
from __future__ import print_function
8
from __future__ import absolute_import
9
from __future__ import division
10
11
# load modules
12
from datetime import datetime
13
14
import os
15
import re
16
import time
17
18
from .media import Media
19
20
21
class Video(Media):
22
23
    """A video object.
24
25
    :param str source: The fully qualified path to the video file.
26
    """
27
28
    __name__ = 'Video'
29
30
    #: Valid extensions for video files.
31
    extensions = ('avi', 'm4v', 'mov', 'mp4', 'mpg', 'mpeg', '3gp', 'mts')
32
33
    def __init__(self, source=None):
34
        super(Video, self).__init__(source)
35
        self.exif_map['date_taken'] = [
36
            'QuickTime:CreationDate',
37
            'QuickTime:CreateDate',
38
            'QuickTime:CreationDate-und-US',
39
            'QuickTime:MediaCreateDate',
40
            'H264:DateTimeOriginal'
41
        ]
42
        self.title_key = 'XMP:DisplayName'
43
        self.latitude_keys = [
44
            'XMP:GPSLatitude',
45
            # 'QuickTime:GPSLatitude',
46
            'Composite:GPSLatitude'
47
        ]
48
        self.longitude_keys = [
49
            'XMP:GPSLongitude',
50
            # 'QuickTime:GPSLongitude',
51
            'Composite:GPSLongitude'
52
        ]
53
        self.latitude_ref_key = 'EXIF:GPSLatitudeRef'
54
        self.longitude_ref_key = 'EXIF:GPSLongitudeRef'
55
        self.set_gps_ref = False
56
57
    def get_date_taken(self):
58
        """Get the date which the photo was taken.
59
60
        The date value returned is defined by the min() of mtime and ctime.
61
62
        :returns: time object or None for non-photo files or 0 timestamp
63
        """
64
        if(not self.is_valid()):
65
            return None
66
67
        source = self.source
68
        seconds_since_epoch = min(os.path.getmtime(source), os.path.getctime(source))  # noqa
69
70
        exif = self.get_exiftool_attributes()
71
        for date_key in self.exif_map['date_taken']:
72
            if date_key in exif:
73
                # Example date strings we want to parse
74
                # 2015:01:19 12:45:11-08:00
75
                # 2013:09:30 07:06:05
76
                date = re.search('([0-9: ]+)([-+][0-9:]+)?', exif[date_key])
77
                if(date is not None):
78
                    date_string = date.group(1)
79
                    date_offset = date.group(2)
80
                    try:
81
                        exif_seconds_since_epoch = time.mktime(
82
                            datetime.strptime(
83
                                date_string,
84
                                '%Y:%m:%d %H:%M:%S'
85
                            ).timetuple()
86
                        )
87
                        if(exif_seconds_since_epoch < seconds_since_epoch):
88
                            seconds_since_epoch = exif_seconds_since_epoch
89
                            if date_offset is not None:
90
                                offset_parts = date_offset[1:].split(':')
91
                                offset_seconds = int(offset_parts[0]) * 3600
92
                                offset_seconds = offset_seconds + int(offset_parts[1]) * 60  # noqa
93
                                if date_offset[0] == '-':
94
                                    seconds_since_epoch - offset_seconds
95
                                elif date_offset[0] == '+':
96
                                    seconds_since_epoch + offset_seconds
97
                    except:
98
                        pass
99
100
        if(seconds_since_epoch == 0):
101
            return None
102
103
        return time.gmtime(seconds_since_epoch)
104