SeriesPlugin 1.3.4: Fixed crash on deactivation of EPG integration
[enigma2-plugins.git] / seriesplugin / src / SeriesPluginRenamer.py
1 # -*- coding: utf-8 -*-
2 #######################################################################
3 #
4 #    Series Plugin for Enigma-2
5 #    Coded by betonme (c) 2012 <glaserfrank(at)gmail.com>
6 #    Support: http://www.i-have-a-dreambox.com/wbb2/thread.php?threadid=TBD
7 #
8 #    This program is free software; you can redistribute it and/or
9 #    modify it under the terms of the GNU General Public License
10 #    as published by the Free Software Foundation; either version 2
11 #    of the License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #######################################################################
19
20 import os
21 import re
22 import glob
23
24 # for localized messages
25 from . import _
26
27 # Config
28 from Components.config import config
29
30 from Screens.MessageBox import MessageBox
31 from Tools.Notifications import AddPopup
32
33 from Tools.BoundFunction import boundFunction
34 from Tools.ASCIItranslit import ASCIItranslit
35
36 from enigma import eServiceCenter, iServiceInformation, eServiceReference
37 from ServiceReference import ServiceReference
38
39 # Plugin internal
40 from SeriesPlugin import getInstance, refactorTitle, refactorDescription   #, refactorRecord
41 from Logger import splog
42
43
44 # By Bin4ry
45 def newLegacyEncode(string):
46         string2 = ""
47         for z, char in enumerate(string.decode("utf-8")):
48                 i = ord(char)
49                 if i < 33:
50                         string2 += " "
51                 elif i in ASCIItranslit:
52                         # There is a bug in the E2 ASCIItranslit some (not all) german-umlaut(a) -> AE
53                         if char.islower():
54                                 string2 += ASCIItranslit[i].lower()
55                         else:
56                                 string2 += ASCIItranslit[i]
57                                 
58                 else:
59                         try:
60                                 string2 += char.encode('ascii', 'strict')
61                         except:
62                                 string2 += " "
63         return string2
64
65 def rename(service, name, short, data):
66         # Episode data available
67         splog("SPR: rename:", data)
68         
69         #MAYBE Check if it is already renamed?
70         try:
71                 # Before renaming change content
72                 renameMeta(service, data)
73                 if config.plugins.seriesplugin.pattern_title.value and not config.plugins.seriesplugin.pattern_title.value == "Off":
74
75                         if config.plugins.seriesplugin.rename_file.value == True:
76                                 renameFile(service, name, data)
77                 #if config.plugins.seriesplugin.pattern_record.value and not config.plugins.seriesplugin.pattern_record.value == "Off":
78                 #       renameFile(service, name, data)
79                 return True
80         except:
81                 #pass
82                 raise
83         return False
84
85 # Adapted from MovieRetitle setTitleDescr
86 def renameMeta(service, data):
87         try:
88                 #TODO Use MetaSupport EitSupport classes from EMC ?
89                 if service.getPath().endswith(".ts"):
90                         meta_file = service.getPath() + ".meta"
91                 else:
92                         meta_file = service.getPath() + ".ts.meta"
93                 
94                 # Create new meta for ts files
95                 if not os.path.exists(meta_file):
96                         if os.path.isfile(service.getPath()):
97                                 _title = os.path.basename(os.path.splitext(service.getPath())[0])
98                         else:
99                                 _title = service.getName()
100                         _sid = ""
101                         _descr = ""
102                         _time = ""
103                         _tags = ""
104                         metafile = open(meta_file, "w")
105                         metafile.write("%s\n%s\n%s\n%s\n%s" % (_sid, _title, _descr, _time, _tags))
106                         metafile.close()
107                 
108                 if os.path.exists(meta_file):
109                         metafile = open(meta_file, "r")
110                         sid = metafile.readline()
111                         oldtitle = metafile.readline().rstrip()
112                         olddescr = metafile.readline().rstrip()
113                         rest = metafile.read()
114                         metafile.close()
115                         
116                         if config.plugins.seriesplugin.pattern_title.value and not config.plugins.seriesplugin.pattern_title.value == "Off":
117                                 title = refactorTitle(oldtitle, data)
118                         else:
119                                 title = oldtitle
120                         splog("SPR: title",title)
121                         if config.plugins.seriesplugin.pattern_description.value and not config.plugins.seriesplugin.pattern_description.value == "Off":
122                                 descr = refactorDescription(olddescr, data)
123                         else:
124                                 descr = olddescr
125                         splog("SPR: descr",descr)
126                         
127                         metafile = open(meta_file, "w")
128                         metafile.write("%s%s\n%s\n%s" % (sid, title, descr, rest))
129                         metafile.close()
130         except Exception as e:
131                 splog("SPR: renameMeta:", e)
132
133 def renameFile(service, name, data, tidy=False):
134         try:
135                 servicepath = service.getPath()
136                 splog("SPR: servicepath", servicepath)
137                 
138                 path = os.path.dirname(servicepath)
139                 file_name = os.path.basename(os.path.splitext(servicepath)[0])
140                 splog("SPR: file_name", file_name)
141                 
142                 splog("SPR: name     ", name)
143                 # Refactor title
144                 if config.plugins.seriesplugin.tidy_rename.value or tidy:
145                         name = refactorTitle(name, data)
146                 else:
147                         name = refactorTitle(file_name, data)
148                 splog("SPR: name     ", name)
149                 if config.plugins.seriesplugin.legacy_rename.value:
150                         name = newLegacyEncode(name)
151                         splog("SPR: name     ", name)
152                 
153                 src = os.path.join(path, file_name)
154                 splog("SPR: servicepathSrc", src)
155                 dst = os.path.join(path, name)
156                 splog("SPR: servicepathDst", dst)
157
158                 for f in glob.glob( glob.escape(src) + "*" ):
159                         splog("SPR: servicepathRnm", f)
160                         to = f.replace(src, dst)
161                         splog("SPR: servicepathTo ", to)
162                         if not os.path.exists(to):
163                                 os.rename(f, to)
164                         elif config.plugins.seriesplugin.rename_existing_files.value:
165                                 splog("SPR: Destination file alreadey exists", to, " - Append _")
166                                 renameFile(service, name + "_", data, True)
167                                 break
168                         else:
169                                 splog("SPR: Destination file alreadey exists", to, " - Skip rename")
170         except Exception as e:
171                 splog("SPR: renameFile:", e)
172
173
174 from ThreadQueue import ThreadQueue
175 from threading import Thread
176 from enigma import ePythonMessagePump
177
178 class SeriesPluginRenameService(Thread):
179         
180         def __init__(self):
181                 Thread.__init__(self)
182                 self.__running = False
183                 self.__messages = ThreadQueue()
184                 self.__messagePump = ePythonMessagePump()
185
186         def __getMessagePump(self):
187                 return self.__messagePump
188         MessagePump = property(__getMessagePump)
189
190         def __getMessageQueue(self):
191                 return self.__messages
192         Message = property(__getMessageQueue)
193
194         def __getRunning(self):
195                 return self.__running
196         isRunning = property(__getRunning)
197
198         def Start(self, services):
199         
200                 if not self.__running:
201                         self.__running = True
202                         self.__services = services
203                         self.start() # Start blocking code in Thread 
204                         
205         def run(self):
206                 
207                 for service in self.__services:
208                         
209                         splog("SPR: run")
210                         seriesPlugin = getInstance()
211                         self.serviceHandler = eServiceCenter.getInstance()
212                         
213                         if isinstance(service, eServiceReference):
214                                 service = service
215                         elif isinstance(service, ServiceReference):
216                                 service = service.ref
217                         else:
218                                 splog("SPR: Wrong instance")
219                                 self.__messages.push(service)
220                                 self.__messagePump.send(0)
221                                 self.__running = False
222                                 Thread.__init__(self)
223                                 return
224                         
225                         if not os.path.exists( service.getPath() ):
226                                 splog("SPR: File not exists: " + service.getPath())
227                                 self.__messages.push(service)
228                                 self.__messagePump.send(0)
229                                 self.__running = False
230                                 Thread.__init__(self)
231                                 return
232                         
233                         info = self.serviceHandler.info(service)
234                         if not info:
235                                 splog("SPR: No info available: " + service.getPath())
236                                 self.__messages.push(service)
237                                 self.__messagePump.send(0)
238                                 self.__running = False
239                                 Thread.__init__(self)
240                                 return 
241                         
242                         name = service.getName() or info.getName(service) or ""
243                         #splog("SPR: name", name)
244                         
245                         short = ""
246                         
247                         event = info.getEvent(service)
248                         if event:
249                                 short = event.getShortDescription()
250                                 begin = event.getBeginTime()
251                                 duration = event.getDuration() or 0
252                                 end = begin + duration or 0
253                                 # We got the exact start times, no need for margin handling
254                         
255                         if not begin:
256                                 begin = info.getInfo(service, iServiceInformation.sTimeCreate) or -1
257                                 if begin != -1:
258                                         end = begin + (info.getLength(service) or 0)
259                                 else:
260                                         end = os.path.getmtime(service.getPath())
261                                         begin = end - (info.getLength(service) or 0)
262                                 #MAYBE we could also try to parse the filename
263                                 # We don't know the exact margins, we will assume the E2 default margins
264                                 begin + (int(config.recording.margin_before.value) * 60)
265                                 end - (int(config.recording.margin_after.value) * 60)
266                         
267                         rec_ref_str = info.getInfoString(service, iServiceInformation.sServiceref)
268                         #channel = ServiceReference(rec_ref_str).getServiceName()
269                         
270                         splog("SPR: getEpisode:", name, begin, end)
271                         seriesPlugin.getEpisode(
272                                         boundFunction(self.serviceCallback, service, name, short),
273                                         name, begin, end, rec_ref_str, elapsed=True
274                                 )
275
276         def serviceCallback(self, service, name, short, data=None):
277                 splog("SPR: serviceCallback", name, data)
278                 
279                 result = None
280                 
281                 if data and len(data) == 4:
282                         if rename(service, name, short, data):
283                                 # Rename was successfully
284                                 result = None
285                 elif data:
286                         result = service.getPath() + " : " + str( data )
287                 else:
288                         result = service.getPath()
289                 
290                 self.__messages.push(result)
291                 self.__messagePump.send(0)
292
293                 self.__running = False
294                 Thread.__init__(self)
295                 splog("SPR: Service done")
296
297                 
298 seriespluginrenameservice = SeriesPluginRenameService()
299
300 #######################################################
301 # Rename movies
302 class SeriesPluginRenamer(object):
303         def __init__(self, session, services, *args, **kwargs):
304                 
305                 splog("SPR: SeriesPluginRenamer")
306                 
307                 if services and not isinstance(services, list):
308                         services = [services]   
309                 
310                 splog("SPR: len()", len(services))
311                 
312                 self.services = services
313                 
314                 self.data = []
315                 self.counter = 0
316                 self.__pump_recv_msg_conn = None
317                 
318                 session.openWithCallback(
319                         self.confirm,
320                         MessageBox,
321                         _("Do You want to start renaming?"),
322                         MessageBox.TYPE_YESNO,
323                         timeout = 15,
324                         default = True
325                 )
326
327         def confirm(self, confirmed):
328                 if confirmed and self.services:
329                         self.__pump_recv_msg_conn = seriespluginrenameservice.MessagePump.recv_msg.connect(self.gotThreadMsg_seriespluginrenameservice) # interconnect to thread start
330                         seriespluginrenameservice.Start(self.services)
331
332         def gotThreadMsg_seriespluginrenameservice(self, msg):
333                 msg = seriespluginrenameservice.Message.pop()
334                 splog("SPR: gotThreadMsg", msg)
335                 self.renamerCallback(msg)
336                 self.__pump_recv_msg_conn = None
337
338         def renamerCallback(self, result=None):
339                 splog("SPR: renamerCallback", result)
340                 
341                 if result and isinstance(result, basestring):
342                         self.data.append( result )
343                 
344                 if config.plugins.seriesplugin.rename_popups.value and config.plugins.seriesplugin.rename_popups_success.value:
345                         
346                         self.counter = self.counter +1
347                         
348                         if self.data or config.plugins.seriesplugin.renamer_popups_success.value:
349                         
350                                 # Maybe there is a better way to avoid multiple Popups
351                                 from SeriesPlugin import seriespluginworker
352                                 
353                                 splog("SPR: renamerCallback getListLength", not seriespluginworker or seriespluginworker.getListLength())
354                                 
355                                 if not seriespluginworker or seriespluginworker.isListEmpty():
356                                         if self.data:
357                                                 AddPopup(
358                                                         "SeriesPlugin:\n" + _("Record rename has been finished with %d errors:\n") % (len(self.data)) +"\n" +"\n".join(self.data),
359                                                         MessageBox.TYPE_ERROR,
360                                                         0,
361                                                         'SP_PopUp_ID_RenameFinished'
362                                                 )
363                                         else:
364                                                 AddPopup(
365                                                         "SeriesPlugin:\n" + _("%d records renamed successfully") % (self.counter),
366                                                         MessageBox.TYPE_INFO,
367                                                         0,
368                                                         'SP_PopUp_ID_RenameFinished'
369                                                 )
370                                         self.data = []
371                                         self.counter = 0