2 from tord
.pyro
import *
3 from tord
.common
import *
5 import pytx
, traceback
, sys
8 sys
.stderr
.write(str(x
))
11 def wrapper(*args
, **kwargs
):
12 try: return f(*args
, **kwargs
)
15 log("error: " + str(f
))
19 def __init__(self
, core
, flags
= 0):
20 pytx
.List
.__init
__(self
, flags
)
26 self
.add(self
.count
, text
)
31 def size_cb(self
, s
, d
):
34 class Status(pytx
.List
):
35 def __init__(self
, core
, flags
= 0):
36 pytx
.List
.__init
__(self
, flags
)
40 if x
> 999: return 'inf'
44 if x
< 0: return 'inf'
47 self
.keys
= ["download_rate", "download_limit", "upload_rate", "upload_limit", "num_peers", "dht_nodes"]
50 "download_rate": lambda x
: speed(x
),
51 "download_limit": lambda x
: speed(x
),
52 "upload_rate": lambda x
: speed(x
),
53 "upload_limit": lambda x
: speed(x
),
54 "num_peers": lambda x
: peers(x
),
55 "dht_nodes": lambda x
: peers(x
),
58 def update(self
, active
=0):
59 data
= self
.core
.get_session_status(self
.keys
)
60 status
= [self
.format
[k
](v
) for k
, v
in zip(self
.keys
, data
)]
61 text
= "Download[%6s|%6s] Upload[%6s|%6s] Peers[%3s] DHT[%3s]" % tuple(status
)
68 def size_cb(self
, s
, d
):
73 self
.name
= 'torrents'
74 self
.keys
= ['state', 'download_payload_rate', 'upload_payload_rate', 'progress', 'eta', 'total_wanted', 'num_peers', 'name']
75 self
.func
= lambda c
, k
, i
, a
, s
: c
.get_torrents_status(i
, k
, a
)
78 'f' : lambda l
,x
: l
.view_change('files', x
),
79 'c' : lambda l
,x
: l
.view_change('config_core', x
),
80 '-' : lambda l
,x
: l
.core
.set_config({"max_upload_speed":20}),
81 'w' : lambda l
,x
: l
.core
.set_torrents_state("write", [x
]),
82 'd' : lambda l
,x
: l
.core
.set_torrents_state("remove", [x
]),
83 'r' : lambda l
,x
: l
.core
.set_torrents_state("resume", [x
]),
84 'R' : lambda l
,x
: l
.core
.set_torrents_state("resume"),
85 'p' : lambda l
,x
: l
.core
.set_torrents_state("pause", [x
]),
86 'P' : lambda l
,x
: l
.core
.set_torrents_state("pause"),
87 't' : lambda l
,x
: l
.core
.set_torrents_state("toggle", [x
]),
88 'D' : lambda l
,x
: l
.core
.remove(x
, True),
89 'y' : lambda l
,x
: l
.columns_swap('progress', '_progress'),
90 'u' : lambda l
,x
: l
.refresh(reset
=True, clear
=True, update
=True, sync
=True),
96 self
.keys
= ['id', 'priority', 'progress', 'path']
98 '[' : lambda l
,x
: l
.core
.torrent_prioritize_files(self
.id, [x
], -1),
99 ']' : lambda l
,x
: l
.core
.torrent_prioritize_files(self
.id, [x
], 1),
100 ',' : lambda l
,x
: self
.select(l
,x
,-1),
101 '.' : lambda l
,x
: self
.select(l
,x
,1),
102 'u' : lambda l
,x
: l
.refresh(update
=True)
107 def func(self
, c
, k
, i
, a
, s
):
108 files
= c
.torrent_get_files(k
,s
)
109 #if s not in self.files:
110 # self.files[s] = self.File(files)
111 #return self.files[s].get(files)
114 def select(self
, l
, x
, b
):
115 remove
= self
.files
[self
.id].update(x
, b
)
117 log (("remove:", [i
for i
in remove
]))
120 l
.refresh(sync
= True, update
= True)
124 self
.name
= 'config_core'
125 self
.keys
= ['key', 'value']
126 self
.func
= lambda c
, k
, i
, a
, s
: c
.get_config()
131 def __init__(self
, func
, title
, t_width
, nt_width
, align
, resize
):
134 self
.t_width
= t_width
135 self
.nt_width
= nt_width
139 def format(self
, text
, width
):
141 return text
.rjust(width
)
143 return text
.ljust(width
)
145 def format_data(self
, data
, width
):
146 return self
.format(self
.func(data
), width
)
148 def format_title(self
, width
):
149 return self
.format(self
.title
, width
)
151 def format_width(self
, title
):
152 if title
: return self
.t_width
159 def add_column(self
, key
, func
, title
, t_width
, nt_width
, align
, resize
):
160 self
.cols
[key
] = Column(func
, title
, t_width
, nt_width
, align
, resize
)
162 def columns_swap(self
, a
, b
):
163 self
.cols
[a
], self
.cols
[b
] = self
.cols
[b
], self
.cols
[a
]
164 self
.refresh(reset
=True)
166 def column_widths(self
, keys
, title
):
167 return [self
.cols
[k
].format_width(title
) for k
in keys
]
169 def column_titles(self
, keys
, widths
):
170 return [self
.cols
[k
].format_title(w
) for k
, w
in zip(keys
, widths
)]
172 def column_data(self
, data
, widths
, keys
):
173 return [self
.cols
[k
].format_data(d
,w
) for d
, w
, k
in zip(data
, widths
, keys
)]
180 def view_add(self
, view
):
181 if not len(self
.views
): self
.view
= view
182 self
.views
[view
.name
] = view
185 def view_change(self
, view
= 'torrents', selected
= None):
186 self
.view
= self
.views
[view
]
187 self
.view
.id = selected
188 self
.refresh(reset
=True, clear
=True, update
=True)
191 return self
.view
.keys
193 def view_data(self
, core
, ids
, active
):
194 return self
.view
.func(core
, self
.get_keys(), ids
, active
, self
.view
.id)
196 def view_bindings(self
, obj
, ch
, id):
197 if chr(ch
) in self
.view
._bindings
:
198 self
.view
._bindings
[chr(ch
)](obj
, id)
201 class List(Columns
, Views
, pytx
.List
):
202 def __init__(self
, core
, get_core
, flags
):
203 pytx
.List
.__init
__(self
, flags
)
204 Columns
.__init
__(self
)
207 self
.get_core
= get_core
210 'g' : lambda x
: self
.view_change(),
211 'S' : lambda x
: self
.toggle_title(),
212 's' : lambda x
: self
.toggle_separator(),
213 'q' : lambda x
: self
.quit(),
224 def refresh(self
, clear
= False, reset
= False, sync
= False, update
= False, active
= False):
225 if clear
: self
.clear()
226 if reset
: self
.reset()
227 if sync
or reset
: self
.sync()
228 if update
: self
.update(self
.get_core(), active
)
233 def toggle_title(self
):
234 self
.flag_toggle(pytx
.TITLES
)
235 self
.refresh(reset
=True)
238 def toggle_separator(self
):
239 self
.flag_toggle(pytx
.SEPARATOR
)
240 self
.refresh(reset
=True)
243 def toggle_acending(self
):
244 self
.refresh(update
=True)
247 def get_id(self
, hash):
248 if hash not in self
.ids
:
249 self
.ids
[hash] = len(self
.ids
)
250 self
.hashs
[self
.ids
[hash]] = hash
251 return self
.ids
[hash]
254 def get_hash(self
, hash):
255 return self
.hashs
[hash]
258 def update(self
, core
, ids
=None, active
=False):
259 for id, row
in self
.view_data(core
, ids
, active
):
260 self
.add(self
.get_id(id), row
)
263 def text_cb(self
, data
):
264 return self
.column_data(data
, self
.widths
, self
.get_keys())
267 def bind_cb(self
, ch
, key
):
269 if chr(ch
) in self
.bindings
: self
.bindings
[chr(ch
)](key
); return
270 if self
.view_bindings(self
, ch
, self
.get_hash(key
)): return
273 if 0 < ch
-48 < len(self
.get_keys()) + 1: self
.sort(ch
-49)
274 if ch
-48 == 0: self
.sort(asc
= not self
.sort_asc_get())
279 self
.update(self
.core
, ids
= None, active
= True)
285 title
= self
.flag_get(pytx
.TITLES
)
286 keys
= self
.get_keys()
287 self
.widths_set(self
.column_widths(keys
, title
))
288 self
.titles_set(self
.column_titles(keys
, self
.widths
))
292 def size_cb(self
, s
, d
):
301 return (x
[1] and "p" or " ") + fstate(x
[0])[0]
304 if x
> 999: return 'inf'
312 return fpcnt_bar(x
, 12)
314 l
= List(self
.core
, self
.get_core
, pytx
.FOCUS|pytx
.SCROLL|pytx
.SEPARATOR|pytx
.TITLES|pytx
.HIGHLIGHT
)
315 l
.view_add(Torrents())
317 l
.view_add(ConfigCore())
319 l
.add_column("state", state
, 'state', 5, 2, 0, False)
320 l
.add_column("eta", ftime
, 'eta', 7, 7, 0, False)
321 l
.add_column("progress", bar
, 'progress', 12, 12, 0, False)
322 l
.add_column("_progress", fpcnt
, 'progress', 8, 8, 0, False)
323 l
.add_column("upload_payload_rate", fspeed
, 'up', 6, 6, 0, False)
324 l
.add_column("download_payload_rate", fspeed
, 'down', 6, 6, 0, False)
325 l
.add_column("total_wanted", fsize
, 'size', 6, 6, 0, False)
326 l
.add_column("num_peers", peers
, 'peers', 5, 3, 0, False)
327 l
.add_column("name", str, 'name', 0, 0, 1, True)
328 l
.add_column("priority", priority
, 'priority', 8, 1, 0, True)
329 l
.add_column("path", str, 'path', 0, 0, 1, True)
330 l
.add_column("id", str, 'id', 3, 3, 0, True)
331 l
.add_column("queue", str, 'queue', 5, 3, 0, True)
333 b
= pytx
.Box(pytx
.VERT
, pytx
.ROOT|pytx
.BORDER
)
335 s
= Status(self
.core
)
341 self
.refresh
= l
.refresh
342 sys
.stderr
= FakeIO(m
.msg
, m
.draw
)
346 self
.core
= self
.get_core()
347 b
,t
,m
,s
= self
.setup()
351 "remove": lambda c
,x
: t
.refresh(reset
=True, clear
=True, update
=True, sync
=True),
354 self
.refresh(update
=True, reset
=True)
361 def message(self
, subject
, msg
):
363 log("%-8s: %s" %( str(alert
), str(msg
)) )
364 if subject
in self
.events
:
365 self
.events
[subject
](self
.get_core(), [msg
])
374 args
= uri
= publish
= None
375 ''' we are going over the internet '''
376 if len(sys
.argv
) == 3:
377 if ping(sys
.argv
[1]):
378 uri
, publish
= sys
.argv
[1], sys
.argv
[2]
379 ''' we are disambiguating network servers '''
380 elif len(sys
.argv
) == 2: args
= sys
.argv
[1]
381 if not uri
: uri
= get_daemon_uri(args
)
382 daemon
= get_daemon(False, True, publish
)
383 ui
= PyroClient(TXTor
, uri
)
384 run(ui
, daemon
, True)
386 if 'ui' in dir(): shutdown(ui
, daemon
)
388 if __name__
== "__main__":