1 # Written by Andrea Reale
2 # see LICENSE.txt for license information
4 from __future__ import with_statement
5 from BaseLib.Core.Subtitles.MetadataDomainObjects.Languages import \
15 class SubtitleInfo(object):
17 Represents a subtitles in a given language.
19 It contains three fields, namely lang (an ISO 693-2 code), path that is
20 the path into the filesystem to the subtitles file, and checksum that is
21 a base64 representation of the sha1 checksum for that file.
22 It also manages the computation and verification of a sha1 checksum for
25 Notice that the path property can be None. This means that tha actual
26 subtitle hasn't been collected and is not available on the local
27 filesystem, In that case the checksum field will be none as well.
29 Also notice that this object is meant to be used as a DTO. Simply changing
30 property in this object won't by themself affect values contained in the
33 SYNCHRONIZATION: This objects act only as copies of the data in the DB.
34 If the instance is nevere passed by between different threads
35 no synchronization is needed.
40 def __init__(self, lang, path=None, checksum=None):
42 Create a subtitle instance.
44 @param lang: an ISO 639-2 language code. Notice that not every language
45 code described by the standard is supported, but only
46 a small subset. See the Languages module
47 @param path: a file system path to the subtitles file
48 @param checksum: a sha1 checksum of the contents
51 self._languages = LanguagesProvider.getLanguagesInstance()
52 if lang not in self._languages.supportedLanguages.keys():
53 raise ValueError("Language" + lang + " not supported")
56 #ISO 639-2 code. See Languages for supported languages
57 self._lang = lang #final property
58 #A string representing the path in the filesystme for this subtitle
61 self._checksum = checksum
66 Returns the language of the subtitle as a three characters code
69 @return: a three characters ISO 639-2 code
73 lang = property(getLang) # "final" property
75 def setPath(self, path):
77 Sets the local path for the subtitle.
79 Calling this method does not change what is stored in the DB. You will
80 have to update that data separately (see L{MetadataDBHandler})
83 @param path: the local path were the subtitle is stored
90 Get the path on the local host for the subtitle file, if available.
93 @return: the local path if the subtitle is locally available. Otherwise
99 path = property(getPath, setPath)
101 def setChecksum(self, checksum):
103 Set the checksum for this subtitle instance.
105 ATTENTION: This method should be never called, but instead a the
106 L{computeChecksum} method should be called instead.
109 @param checksum: a 160bit sha1 checksum of the subtitle
111 self._checksum = checksum
114 def getChecksum(self):
116 Returns the SHA-1 checksum of the subtitle.
119 @return: a 20byte string representing the SHA-1 checksum of the
122 return self._checksum
125 checksum = property(getChecksum, setChecksum)
127 def subtitleExists(self):
129 Checks wheter a subtitle exist in its specified path.
131 @return: True if self.path is pointing to a local existing file.
135 if self.path is None:
137 return os.path.isfile(self.path)
140 def computeChecksum(self):
142 Computes the checksum of the file containing the subtitles
143 and sets its corresponding property.
145 @precondition: self.subtitleExists()
146 @postcondition: self.checksum is not None
149 assert self.subtitleExists()
151 self.checksum = self._doComputeChecksum()
154 def _doComputeChecksum(self):
156 Computes the checksum of the file containing the subtitles
158 @precondition: self.subtitleExists()
161 with codecs.open(self.path, "rb", "utf-8", "replace") as subFile:
162 content = subFile.read()
164 hasher = hashlib.sha1()
165 hasher.update(content.encode('utf-8','replace'))
167 return hasher.digest()
170 print >> sys.stderr, "Warning: Unable to open " + self.path + " for reading"
174 def verifyChecksum(self):
176 Verifies the checksum of the file containing the subtitles.
178 Computes the checksum of the file pointed by self.path
179 and checks whether it is equal to the one in self.checksum
181 @precondition: self.subtitleExists()
182 @precondition: self.checksum is not None
185 @return: True if the verification is ok.
187 @raises AssertionError: if one of the preconditions does not hold
190 assert self.subtitleExists(), "Cannot compute checksum: subtitle file not found"
191 assert self.checksum is not None, "Cannot verify checksum: no checksum to compare with"
193 computed = self._doComputeChecksum()
194 return computed == self.checksum
199 if self.path is not None:
203 return "subtitle: [lang=" + self.lang +"; path=" + path \
204 + "; sha1=" + base64.encodestring(self.checksum).rstrip() + "]"
207 def __eq__(self,other):
209 Test instances of SubtitleInfo for equality.
211 Two subtitle instances are considered equal if they have the same
212 language and the same file checksum
217 return self.lang == other.lang and self.checksum == other.checksum
218 #and self.path == other.path
222 def __ne__(self,other):
223 return not self.__eq__(other)