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