instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Core / Subtitles / MetadataDomainObjects / SubtitleInfo.py
1 # Written by Andrea Reale
2 # see LICENSE.txt for license information
3
4 from __future__ import with_statement
5 from BaseLib.Core.Subtitles.MetadataDomainObjects.Languages import \
6     LanguagesProvider
7 import base64
8 import codecs
9 import hashlib
10 import os.path
11 import sys
12
13 DEBUG = False
14
15 class SubtitleInfo(object):
16     '''
17     Represents a subtitles in a given language.
18     
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 
23     a the subtitle.
24         
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.
28     
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
31     Database
32     
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. 
36     '''
37
38     
39
40     def __init__(self, lang, path=None, checksum=None):
41         """
42         Create a subtitle instance.
43         
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 
49                          of the subitles file
50         """
51         self._languages = LanguagesProvider.getLanguagesInstance()
52         if lang not in self._languages.supportedLanguages.keys():
53             raise ValueError("Language" + lang + " not supported")
54         
55         
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
59         self._path = path
60         #sha1 checksum
61         self._checksum = checksum
62         
63             
64     def getLang(self):
65         '''
66         Returns the language of the subtitle as a three characters code
67
68         @rtype: str
69         @return: a three characters ISO 639-2 code
70         '''
71         return self._lang
72
73     lang = property(getLang) # "final" property
74         
75     def setPath(self, path):
76         '''
77         Sets the local path for the subtitle. 
78
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})
81
82         @type path: str
83         @param path: the local path were the subtitle is stored
84         '''
85         self._path = path
86
87             
88     def getPath(self):
89         '''
90         Get the path on the local host for the subtitle file, if available.
91
92         @rtype: str
93         @return: the local path if the subtitle is locally available. Otherwise
94             None.
95         '''
96         return self._path
97
98     
99     path = property(getPath, setPath)
100             
101     def setChecksum(self, checksum):
102         '''
103         Set the checksum for this subtitle instance. 
104
105         ATTENTION: This method should be never called, but instead a the
106         L{computeChecksum} method should be called instead.
107
108         @type checksum: str
109         @param checksum: a 160bit sha1 checksum of the subtitle
110         '''
111         self._checksum = checksum
112
113             
114     def getChecksum(self):
115         '''
116         Returns the SHA-1 checksum of the subtitle.
117
118         @rtype: str
119         @return: a 20byte string representing the SHA-1 checksum of the
120             subtitle
121         '''
122         return self._checksum
123
124         
125     checksum = property(getChecksum, setChecksum)
126         
127     def subtitleExists(self):
128         """
129         Checks wheter a subtitle exist in its specified path.
130         
131         @return: True if self.path is pointing to a local existing file.
132             Otherwise false
133         """
134
135         if self.path is None:
136             return False
137         return os.path.isfile(self.path)
138
139     
140     def computeChecksum(self):
141         """
142         Computes the checksum of the file containing the subtitles
143         and sets its corresponding property.
144
145         @precondition: self.subtitleExists()
146         @postcondition: self.checksum is not None
147         """
148  
149         assert self.subtitleExists()
150
151         self.checksum = self._doComputeChecksum()
152  
153         
154     def _doComputeChecksum(self):
155         """
156         Computes the checksum of the file containing the subtitles
157         
158         @precondition: self.subtitleExists()
159         """
160         try:
161             with codecs.open(self.path, "rb", "utf-8", "replace") as subFile:
162                 content = subFile.read()
163       
164             hasher = hashlib.sha1()
165             hasher.update(content.encode('utf-8','replace'))
166             
167             return hasher.digest()
168         
169         except IOError:
170             print >> sys.stderr, "Warning: Unable to open " + self.path + " for reading"
171  
172         
173     
174     def verifyChecksum(self):
175         """
176         Verifies the checksum of the file containing the subtitles.
177         
178         Computes the checksum of the file pointed by self.path
179         and checks whether it is equal to the one in self.checksum
180         
181         @precondition: self.subtitleExists()
182         @precondition: self.checksum is not None
183
184         @rtype: boolean
185         @return: True if the verification is ok.
186
187         @raises AssertionError: if one of the preconditions does not hold
188         """
189
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"
192         
193         computed = self._doComputeChecksum()
194         return computed == self.checksum
195
196     
197     def __str__(self):
198
199         if self.path is not None:
200             path = self.path
201         else:
202             path = "None"
203         return "subtitle: [lang=" + self.lang +"; path=" + path \
204                 + "; sha1=" + base64.encodestring(self.checksum).rstrip() + "]"
205
206             
207     def __eq__(self,other):
208         '''
209         Test instances of SubtitleInfo for equality.
210         
211         Two subtitle instances are considered equal if they have the same
212         language and the same file checksum
213         '''
214
215         if self is other:
216             return True
217         return self.lang == other.lang and self.checksum == other.checksum
218                 #and self.path == other.path
219
220                 
221         
222     def __ne__(self,other):
223         return not self.__eq__(other)
224         
225         
226