Completed
Push — master ( 4a7df2...0864f5 )
by Jaisen
01:12
created

Text.get_original_name()   A

Complexity

Conditions 3

Duplication

Lines 0
Ratio 0 %

Size

Total Lines 9

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
"""
2
The text module provides a base :class:`Text` class for text files that
3
are tracked by Elodie.
4
5
.. moduleauthor:: Jaisen Mathai <[email protected]>
6
"""
7
8
from json import dumps, loads
9
import os
10
from shutil import copyfileobj
11
import time
12
13
# load modules
14
from elodie import log
15
from elodie.media.base import Base
16
17
18
class Text(Base):
19
20
    """The class for all text files.
21
22
    :param str source: The fully qualified path to the text file.
23
    """
24
25
    __name__ = 'Text'
26
27
    #: Valid extensions for text files.
28
    extensions = ('txt',)
29
30
    def __init__(self, source=None):
31
        super(Text, self).__init__(source)
32
        self.reset_cache()
33
34
    def get_album(self):
35
        self.parse_metadata_line()
36
        if(not isinstance(self.metadata_line, dict) or
37
                'album' not in self.metadata_line):
38
            return None
39
40
        return self.metadata_line['album']
41
42
    def get_coordinate(self, type='latitude'):
43
        self.parse_metadata_line()
44
        if not self.metadata_line:
45
            return None
46
        elif type in self.metadata_line:
47
            if type == 'latitude':
48
                return self.metadata_line['latitude'] or None
49
            elif type == 'longitude':
50
                return self.metadata_line['longitude'] or None
51
52
        return None
53
54
    def get_date_taken(self):
55
        source = self.source
56
        self.parse_metadata_line()
57
58
        # We return the value if found in metadata
59
        if(isinstance(self.metadata_line, dict) and
60
                'date_taken' in self.metadata_line):
61
            return time.gmtime(self.metadata_line['date_taken'])
62
63
        # If there's no date_taken in the metadata we return
64
        #   from the filesystem
65
        seconds_since_epoch = min(
66
            os.path.getmtime(source),
67
            os.path.getctime(source)
68
        )
69
        return time.gmtime(seconds_since_epoch)
70
71
    def get_metadata(self):
72
        self.parse_metadata_line()
73
        return super(Text, self).get_metadata()
74
75
    def get_original_name(self):
76
        self.parse_metadata_line()
77
78
        # We return the value if found in metadata
79
        if(isinstance(self.metadata_line, dict) and
80
                'original_name' in self.metadata_line):
81
            return self.metadata_line['original_name']
82
83
        return super(Text, self).get_original_name()
84
85
    def get_title(self):
86
        self.parse_metadata_line()
87
88
        if(not isinstance(self.metadata_line, dict) or
89
                'title' not in self.metadata_line):
90
            return None
91
92
        return self.metadata_line['title']
93
94
    def reset_cache(self):
95
        """Resets any internal cache
96
        """
97
        self.metadata_line = None
98
        super(Text, self).reset_cache()
99
100
    def set_album(self, name):
101
        status = self.write_metadata(album=name)
102
        self.reset_cache()
103
        return status
104
105
    def set_date_taken(self, passed_in_time):
106
        if(time is None):
107
            return False
108
109
        seconds_since_epoch = time.mktime(passed_in_time.timetuple())
110
        status = self.write_metadata(date_taken=seconds_since_epoch)
111
        self.reset_cache()
112
        return status
113
114
    def set_original_name(self):
115
        """Sets the original name if not already set.
116
117
        :returns: True, False, None
118
        """
119
        if(not self.is_valid()):
120
            return None
121
122
        # If EXIF original name tag is set then we return.
123
        if self.get_original_name() is not None:
124
            return None
125
126
        source = self.source
127
        name = os.path.basename(source)
128
        status = self.write_metadata(original_name=name)
129
        self.reset_cache()
130
        return status
131
132
    def set_location(self, latitude, longitude):
133
        status = self.write_metadata(latitude=latitude, longitude=longitude)
134
        self.reset_cache()
135
        return status
136
137
    def parse_metadata_line(self):
138
        if isinstance(self.metadata_line, dict):
139
            return self.metadata_line
140
141
        source = self.source
142
        if source is None:
143
            return None
144
145
        with open(source, 'r') as f:
146
            first_line = f.readline().strip()
147
148
        try:
149
            parsed_json = loads(first_line)
150
            if isinstance(parsed_json, dict):
151
                self.metadata_line = parsed_json
152
        except ValueError:
153
            log.error('Could not parse JSON from first line: %s' % first_line)
154
            pass
155
156
    def write_metadata(self, **kwargs):
157
        if len(kwargs) == 0:
158
            return False
159
160
        source = self.source
161
162
        self.parse_metadata_line()
163
164
        # Set defaults for a file without metadata
165
        # Check if self.metadata_line is set and use that instead
166
        metadata_line = {}
167
        has_metadata = False
168
        if isinstance(self.metadata_line, dict):
169
            metadata_line = self.metadata_line
170
            has_metadata = True
171
172
        for name in kwargs:
173
            metadata_line[name] = kwargs[name]
174
175
        metadata_as_json = dumps(metadata_line)
176
        if has_metadata:
177
            # Update the first line of this file in place
178
            # http://stackoverflow.com/a/14947384
179
            with open(source, 'r') as f_read:
180
                f_read.readline()
181
                with open(source, 'w') as f_write:
182
                    f_write.write("{}\n".format(metadata_as_json))
183
                    copyfileobj(f_read, f_write)
184
        else:
185
            # Prepend the metadata to the file
186
            with open(source, 'r') as f_read:
187
                original_contents = f_read.read()
188
                with open(source, 'w') as f_write:
189
                    f_write.write("{}\n{}".format(
190
                        metadata_as_json,
191
                        original_contents)
192
                    )
193
194
        self.reset_cache()
195
        return True
196