emission: initial checkin to this repository
[enigma2-plugins.git] / emission / src / EmissionDetailview.py
1 # -*- coding: utf-8 -*-
2
3 # GUI (Screens)
4 from Screens.Screen import Screen
5 from Screens.MessageBox import MessageBox
6 from Screens.ChoiceBox import ChoiceBox
7 from Screens.HelpMenu import HelpableScreen
8
9 # GUI (Components)
10 from Components.ActionMap import HelpableActionMap
11 from Components.Sources.List import List
12 from Components.Sources.Progress import Progress
13 from Components.Sources.StaticText import StaticText
14
15 from enigma import eTimer
16
17 from . import EmissionBandwidth
18
19 class EmissionDetailview(Screen, HelpableScreen):
20         skin = """<screen name="EmissionDetailview" title="Torrent View" position="75,75" size="565,450">
21                 <ePixmap position="0,0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
22                 <ePixmap position="140,0" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
23                 <ePixmap position="280,0" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
24                 <ePixmap position="420,0" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
25                 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
26                 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
27                 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
28                 <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
29                 <eLabel position="450,45" text="DL: " size="30,20" font="Regular;18" />
30                 <widget source="downspeed" render="Label" position="480,45" size="85,20" halign="right" font="Regular;18" />
31                 <eLabel position="450,67" text="UL: " size="30,20" font="Regular;18" transparent="1" />
32                 <widget source="upspeed" render="Label" position="480,67" size="85,20" halign="right" font="Regular;18" />
33                 <widget source="name" render="Label" position="5,45" size="445,20" font="Regular;18" />
34                 <widget source="peers" render="Label" position="5,67" size="445,20" font="Regular;18" />
35                 <!-- XXX: the actual uri might end up in the next line, this sucks :-) -->
36                 <widget source="tracker" render="Label" position="5,90" size="555,20" font="Regular;18" />
37                 <widget source="private" render="Label" position="5,113" size="555,20" font="Regular;18" />
38                 <widget source="eta" render="Label" position="5,170" size="555,20" font="Regular;18" />
39                 <widget source="progress_text" render="Label" position="5,195" size="400,20" font="Regular;18" />
40                 <widget source="ratio" render="Label" position="410,195" size="150,20" font="Regular;18" halign="right" />
41                 <widget source="progress" render="Progress" position="5,220" size="555,6" />
42                 <widget source="files_text" render="Label" position="5,230" size="100,20" font="Regular;18" />
43                 <widget source="files" render="Listbox" position="0,255" size="566,185" scrollbarMode="showAlways">
44                         <convert type="TemplatedMultiContent">
45                                 {"template": [
46                                                 MultiContentEntryText(pos=(2,2), size=(560,22), text = 4, font = 0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
47                                                 MultiContentEntryText(pos=(2,26), size=(110,20), text = "Downloaded", font = 1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
48                                                 MultiContentEntryText(pos=(117,26), size=(100,20), text = 2, font = 1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
49                                                 MultiContentEntryText(pos=(365,26), size=(70,20), text = "Total", font = 1, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER),
50                                                 MultiContentEntryText(pos=(435,26), size=(100,20), text = 5, font = 1, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER),
51                                                 MultiContentEntryText(pos=(220,26), size=(160,20), text = 6, font = 1, flags = RT_VALIGN_CENTER),
52                                                 (eListboxPythonMultiContent.TYPE_PROGRESS, 0, 47, 540, 6, -7),
53                                         ],
54                                   "fonts": [gFont("Regular", 20),gFont("Regular", 18)],
55                                   "itemHeight": 54
56                                  }
57                         </convert>
58                 </widget>
59         </screen>"""
60
61         def __init__(self, session, daemon, torrent, prevFunc = None, nextFunc = None):
62                 Screen.__init__(self, session)
63                 HelpableScreen.__init__(self)
64                 self.transmission = daemon
65                 self.torrentid = torrent.id
66                 self.prevFunc = prevFunc
67                 self.nextFunc = nextFunc
68
69                 self["ChannelSelectBaseActions"] = HelpableActionMap(self, "ChannelSelectBaseActions",
70                 {
71                         "prevMarker": (self.prevDl, _("show previous download details")),
72                         "nextMarker": (self.nextDl, _("show next download details")),
73                 })
74
75                 self["SetupActions"] = HelpableActionMap(self, "SetupActions",
76                 {
77                         "ok": (self.ok, _("toggle file status")),
78                         "cancel": self.close,
79                 })
80
81                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
82                 {
83                         "yellow": (self.toggleStatus, _("toggle download status")),
84                         "green": (self.bandwidth, _("open bandwidth settings")),
85                         "blue": (self.remove , _("remove torrent")),
86                 })
87
88                 self["key_red"] = StaticText(_("Close"))
89                 self["key_green"] = StaticText(_("Bandwidth"))
90                 if torrent.status == "stopped":
91                         self["key_yellow"] = StaticText(_("start"))
92                 else:
93                         self["key_yellow"] = StaticText(_("stop"))
94                 self["key_blue"] = StaticText(_("remove"))
95
96                 self["upspeed"] = StaticText("")
97                 self["downspeed"] = StaticText("")
98                 self["peers"] = StaticText("")
99                 self["name"] = StaticText(str(torrent.name))
100                 self["files_text"] = StaticText(_("Files"))
101                 self["files"] = List([])
102                 self["progress"] = Progress(int(torrent.progress))
103                 self["progress_text"] = StaticText("")
104                 self["ratio"] = StaticText("")
105                 self["eta"] = StaticText("")
106                 self["tracker"] = StaticText("")
107                 self["private"] = StaticText("")
108
109                 self.timer = eTimer()
110                 self.timer.callback.append(self.updateList)
111                 self.timer.start(0, 1)
112
113         def bandwidthCallback(self, ret = None):
114                 if ret:
115                         try:
116                                 self.transmission.change([self.torrentid], **ret)
117                         except transmission.TransmissionError as te:
118                                 self.session.open(
119                                         MessageBox,
120                                         _("Error communicating with transmission-daemon: %s.") % (te),
121                                         type = MessageBox.TYPE_ERROR,
122                                         timeout = 5
123                                 )
124                 self.updateList()
125
126         def bandwidth(self):
127                 #reload(EmissionBandwidth)
128                 self.timer.stop()
129                 id = self.torrentid
130                 try:
131                         torrent = self.transmission.info([id])[id]
132                         rpc_version = self.transmission.rpc_version
133                 except transmission.TransmissionError as te:
134                         self.session.open(
135                                 MessageBox,
136                                 _("Error communicating with transmission-daemon: %s.") % (te),
137                                 type = MessageBox.TYPE_ERROR,
138                                 timeout = 5
139                         )
140                         # XXX: this seems silly but cleans the gui and restarts the timer :-)
141                         self.updateList()
142                 else:
143                         self.session.openWithCallback(
144                                 self.bandwidthCallback,
145                                 EmissionBandwidth.EmissionBandwidth,
146                                 torrent,
147                                 True,
148                                 rpc_version
149                         )
150
151         def prevDl(self):
152                 if self.prevFunc:
153                         torrent = self.prevFunc()
154                         if torrent:
155                                 self.timer.stop()
156                                 self.torrentid = torrent.id
157                                 self["name"].text = str(torrent.name)
158                                 self.updateList()
159
160         def nextDl(self):
161                 if self.nextFunc:
162                         torrent = self.nextFunc()
163                         if torrent:
164                                 self.timer.stop()
165                                 self.torrentid = torrent.id
166                                 self["name"].text = str(torrent.name)
167                                 self.updateList()
168
169         def toggleStatus(self):
170                 id = self.torrentid
171                 try:
172                         torrent = self.transmission.info([id])[id]
173                         status = torrent.status
174                         if status == "stopped":
175                                 self.transmission.start([id])
176                                 self["key_yellow"].text = _("pause")
177                         elif status in ("downloading", "seeding"):
178                                 self.transmission.stop([id])
179                                 self["key_yellow"].text = _("start")
180                 except transmission.TransmissionError as te:
181                         self.session.open(
182                                 MessageBox,
183                                 _("Error communicating with transmission-daemon: %s.") % (te),
184                                 type = MessageBox.TYPE_ERROR,
185                                 timeout = 5
186                         )
187
188         def remove(self):
189                 self.session.openWithCallback(
190                         self.removeCallback,
191                         ChoiceBox,
192                         _("Really delete torrent?"),
193                         [(_("no"), "no"),
194                         (_("yes"), "yes"),
195                         (_("yes, including data"), "data")]
196                 )
197
198         def removeCallback(self, ret = None):
199                 if ret:
200                         ret = ret[1]
201                         try:
202                                 if ret == "yes":
203                                         self.transmission.remove([self.torrentid], delete_data = False)
204                                         self.close()
205                                 elif ret == "data":
206                                         self.transmission.remove([self.torrentid], delete_data = True)
207                                         self.close()
208                         except transmission.TransmissionError as te:
209                                 self.session.open(
210                                         MessageBox,
211                                         _("Error communicating with transmission-daemon: %s.") % (te),
212                                         type = MessageBox.TYPE_ERROR,
213                                         timeout = 5
214                                 )
215
216         def updateList(self, *args, **kwargs):
217                 id = self.torrentid
218                 try:
219                         torrent = self.transmission.info([id])[id]
220                 except transmission.TransmissionError:
221                         self["upspeed"].text = ""
222                         self["downspeed"].text = ""
223                         self["peers"].text = ""
224                         self["progress_text"].text = ""
225                         self["ratio"].text = ""
226                         self["eta"].text = ""
227                         self["tracker"].text = ""
228                         self["private"].text = ""
229                         self["files"].setList([])
230                 else:
231                         self["upspeed"].text = _("%d kb/s") % (torrent.rateUpload / 1024)
232                         self["downspeed"].text = _("%d kb/s") % (torrent.rateDownload / 1024)
233                         self["progress"].setValue(int(torrent.progress))
234
235                         status = torrent.status
236                         progressText = ''
237                         if status == 'check pending':
238                                 peerText = _("check pending") # ???
239                         elif status == 'checking':
240                                 peerText = _("checking")
241                                 progressText = str(torrent.recheckProgress) # XXX: what is this? :D
242                         elif status == 'downloading':
243                                 peerText = _("Downloading from %d of %d peers") % (torrent.peersSendingToUs, torrent.peersConnected)
244                                 progressText = _("Downloaded %d of %d MB (%d%%)") % (torrent.downloadedEver/1048576, torrent.sizeWhenDone/1048576, torrent.progress)
245                         elif status == 'seeding':
246                                 peerText = _("Seeding to %d of %d peers") % (torrent.peersGettingFromUs, torrent.peersConnected)
247                                 progressText = _("Downloaded %d and uploaded %d MB") % (torrent.downloadedEver/1048576, torrent.uploadedEver/1048576)
248                         elif status == 'stopped':
249                                 peerText = _("stopped")
250                                 progressText = _("Downloaded %d and uploaded %d MB") % (torrent.downloadedEver/1048576, torrent.uploadedEver/1048576)
251                         self["peers"].text = peerText
252                         self["progress_text"].text = progressText
253                         self["ratio"].text = _("Ratio: %.2f") % (torrent.ratio)
254                         self["eta"].text = _("Remaining: %s") % (torrent.eta or '?:??:??')
255
256                         # XXX: we should not need to set this all the time but when we enter this screen we just don't have this piece of information
257                         trackers = torrent.trackers
258                         if trackers:
259                                 self["tracker"].text = str(_("Tracker: %s") % (trackers[0]['announce']))
260                         self["private"].text = _("Private: %s") % (torrent.isPrivate and _("yes") or _("no"))
261
262                         l = []
263                         files = torrent.files()
264                         for id, x in files.items():
265                                 completed = x['completed']
266                                 size = x['size'] or 1 # to avoid division by zero ;-)
267                                 l.append((id, x['priority'], str(completed/1048576) + " MB", \
268                                         x['selected'], str(x['name']), str(size/1048576) + " MB", \
269                                         x['selected'] and _("downloading") or _("skipping"), \
270                                         int(100*(completed / float(size)))
271                                 ))
272
273                         index = min(self["files"].index, len(l)-1)
274                         self["files"].setList(l)
275                         self["files"].index = index
276                 self.timer.startLongTimer(5)
277
278         def ok(self):
279                 cur = self["files"].getCurrent()
280                 if cur:
281                         self.timer.stop()
282                         id = self.torrentid
283                         try:
284                                 torrent = self.transmission.info([id])[id]
285                                 files = torrent.files()
286
287                                 # XXX: we need to make sure that at least one file is selected for
288                                 # download so unfortunately we might have to check all files if
289                                 # we are unselecting this one
290                                 if cur[3]:
291                                         files[cur[0]]['selected'] = False
292                                         atLeastOneSelected = False
293                                         for file in files.values():
294                                                 if file['selected']:
295                                                         atLeastOneSelected = True
296                                                         break
297                                         if not atLeastOneSelected:
298                                                 self.session.open(
299                                                         MessageBox,
300                                                         _("Unselecting the only file scheduled for download is not possible through RPC."),
301                                                         type = MessageBox.TYPE_ERROR
302                                                 )
303                                                 self.updateList()
304                                                 return
305                                 else:
306                                         files[cur[0]]['selected'] = True
307
308                                 self.transmission.set_files({self.torrentid: files})
309                         except transmission.TransmissionError as te:
310                                 self.session.open(
311                                         MessageBox,
312                                         _("Error communicating with transmission-daemon: %s.") % (te),
313                                         type = MessageBox.TYPE_ERROR,
314                                         timeout = 5
315                                 )
316                         self.updateList()
317
318         def close(self):
319                 self.timer.stop()
320                 Screen.close(self)
321