# Written by Jie Yang, Arno Bakker
# see LICENSE.txt for license information
import wx
from wx.lib import masked
import os
from base64 import encodestring
from Swapper.CacheDB.CacheDBHandler import TorrentDBHandler,MyPreferenceDBHandler
from Swapper.utilities import friendly_time,sort_dictlist
from Swapper.unicode import str2unicode,dunno2unicode
from common import CommonSwapperList
from Utility.constants import *#IGNORE:W0611
DEBUG = False
SHOW_TORRENT_NAME = True
relevance_display_factor = 1000.0
def showInfoHash(infohash):
if infohash.startswith('torrent'): # for testing
return infohash
try:
n = int(infohash)
return str(n)
except:
pass
return encodestring(infohash).replace("\n","")
# try:
# return encodestring(infohash)
# except:
# return infohash
class MyPreferenceList(CommonSwapperList):
def __init__(self, parent):
self.parent = parent
self.utility = parent.utility
self.mypref_db = parent.mypref_db
self.min_rank = -1
self.max_rank = 5
self.reversesort = 0
self.lastcolumnsorted = -1
style = wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES
prefix = 'mypref'
minid = 0
maxid = 5
rightalign = []
centeralign = [
MYPREF_TORRENTNAME,
MYPREF_CONTENTNAME,
MYPREF_RANK,
MYPREF_SIZE,
MYPREF_LASTSEEN,
]
exclude = []
self.keys = ['torrent_name', 'content_name', 'rank', 'length', 'last_seen']
CommonSwapperList.__init__(self, parent, style, prefix, minid, maxid,
exclude, rightalign, centeralign)
# change display format for item data
def getText(self, data, row, col):
key = self.keys[col]
original_data = data[row][key]
if DEBUG:
print "mypref frame: getText",key, `original_data`
if key == 'length':
length = original_data/1024/1024.0
return '%.2f MB'%(length)
if key == 'last_seen':
if original_data == 0:
return '?'
return friendly_time(original_data)
ret = str2unicode(original_data)
return ret
def reloadData(self):
myprefs = self.mypref_db.getPrefList()
keys = ['infohash', 'torrent_name', 'info', 'content_name', 'rank', 'last_seen']
self.data = self.mypref_db.getPrefs(myprefs, keys)
for i in xrange(len(self.data)):
info = self.data[i]['info']
self.data[i]['length'] = info.get('length', 0)
if self.data[i]['torrent_name'] == '':
self.data[i]['torrent_name'] = '?'
if self.data[i]['content_name'] == '':
self.data[i]['content_name'] = '?'
def OnActivated(self, event):
self.curr_idx = event.m_itemIndex
def getMenuItems(self, min_rank, max_rank):
menu_items = {}
for i in range(min_rank, max_rank+1):
id = wx.NewId()
func = 'OnRank' + str(i - min_rank)
func = getattr(self, func)
if i == -1:
label = "Fake File"
elif i == 0:
label = "No Rate"
else:
label = "*" * i
menu_items[i] = {'id':id, 'func':func, 'label':label}
return menu_items
def OnRightClick(self, event=None):
curr_idx = self.getSelectedItems()
if not hasattr(self, "adjustRankID"):
self.adjustRankID = wx.NewId()
self.menu_items = self.getMenuItems(self.min_rank, self.max_rank)
for i in self.menu_items:
self.Bind(wx.EVT_MENU, self.menu_items[i]['func'],
id=self.menu_items[i]['id'])
if not hasattr(self, "deletePrefID"):
self.deletePrefID = wx.NewId()
self.Bind(wx.EVT_MENU, self.OnDeletePref, id=self.deletePrefID)
# menu for change torrent's rank
sm = wx.Menu()
curr_rank = self.data[curr_idx[0]]['rank']
for i in curr_idx[1:]:
if self.data[i]['rank'] != curr_rank:
curr_rank = None
submenu = wx.Menu()
idx = self.menu_items.keys()
idx.sort()
idx.reverse()
for i in idx: # 5..-1
if i == curr_rank:
label = '> '+self.menu_items[i]['label']
else:
label = ' '+self.menu_items[i]['label']
submenu.Append(self.menu_items[i]['id'], label)
sm.AppendMenu(self.adjustRankID, "Rank items", submenu)
sm.Append(self.deletePrefID, 'Delete')
self.PopupMenu(sm, event.GetPosition())
sm.Destroy()
def changeRank(self, curr_idx, rank):
torrent = self.data[curr_idx]
torrent['rank'] = rank
self.mypref_db.updateRank(torrent['infohash'], rank)
self.loadList(False, False)
#self.SetStringItem(curr_idx, 2, str(rank))
#print "Set torrent", showInfoHash(torrent['infohash']), "rank", rank
def OnRank0(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 0+self.min_rank)
def OnRank1(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 1+self.min_rank)
def OnRank2(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 2+self.min_rank)
def OnRank3(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 3+self.min_rank)
def OnRank4(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 4+self.min_rank)
def OnRank5(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 5+self.min_rank)
def OnRank6(self, event=None):
selected = self.getSelectedItems()
for i in selected:
self.changeRank(i, 6+self.min_rank)
def OnDeletePref(self, event=None):
selected = self.getSelectedItems()
j = 0
for i in selected:
infohash = self.data[i-j]['infohash']
self.mypref_db.deletePreference(infohash)
self.DeleteItem(i-j)
self.data.pop(i-j)
j += 1
self.mypref_db.sync()
class MyPreferencePanel(wx.Panel):
def __init__(self, frame, parent):
self.parent = parent
self.utility = frame.utility
self.mypref_db = frame.mypref_db
self.torrent_db = frame.torrent_db
wx.Panel.__init__(self, parent, -1)
mainbox = wx.BoxSizer(wx.VERTICAL)
self.list=MyPreferenceList(self)
mainbox.Add(self.list, 1, wx.EXPAND|wx.ALL, 5)
label = wx.StaticText(self, -1, "Right click on a torrent to assign a 1--5 star rating")
mainbox.Add(label, 0, wx.ALIGN_CENTER_VERTICAL)
self.SetSizer(mainbox)
self.SetAutoLayout(True)
self.Show(True)
self.list.loadList()
def updateColumns(self, force=False):
self.list.loadList(False, False)
class FileList(CommonSwapperList):
def __init__(self, parent):
self.parent = parent
self.utility = parent.utility
self.torrent_db = parent.torrent_db
self.min_rank = -1
self.max_rank = 5
self.reversesort = 0
self.lastcolumnsorted = -1
self.loadRelevanceThreshold()
style = wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES
prefix = 'torrent'
minid = 0
maxid = 10
rightalign = []
centeralign = [
TORRENT_TORRENTNAME,
TORRENT_CONTENTNAME,
TORRENT_RECOMMENDATION,
TORRENT_SOURCES,
TORRENT_SIZE,
TORRENT_NFILES,
TORRENT_INJECTED,
TORRENT_TRACKER,
TORRENT_NLEECHERS,
TORRENT_NSEEDERS,
]
exclude = []
self.keys = ['torrent_name', 'content_name', 'relevance', 'num_owners',
'length', 'num_files', 'date', 'tracker', 'leecher', 'seeder'
]
CommonSwapperList.__init__(self, parent, style, prefix, minid, maxid,
exclude, rightalign, centeralign)
# change display format for item data
def getText(self, data, row, col):
key = self.keys[col]
original_data = data[row][key]
if key == 'relevance':
# should this change, also update
return '%.2f'%(original_data/relevance_display_factor)
if key == 'infohash':
return showInfoHash(original_data)
if key == 'length':
length = original_data/1024/1024.0
return '%.2f MB'%(length)
if key == 'date':
if original_data == 0:
return '?'
return friendly_time(original_data)
# if key == 'seeder' or key == 'leecher':
# if original_data < 0:
# return '?'
return str2unicode(original_data)
def reloadData(self):
def showFile(data):
if data['relevance'] < self.relevance_threshold or \
not data['torrent_name'] or not data['info']:
return False
src = os.path.join(data['torrent_dir'], data['torrent_name'])
return os.path.isfile(src)
key = ['infohash', 'torrent_name', 'torrent_dir', 'relevance', 'info',
'num_owners', 'leecher', 'seeder']
self.data = self.torrent_db.getRecommendedTorrents(key)
self.data = filter(showFile, self.data)
for i in xrange(len(self.data)):
info = self.data[i]['info']
self.data[i]['length'] = info.get('length', 0)
self.data[i]['content_name'] = dunno2unicode(info.get('name', '?'))
if self.data[i]['torrent_name'] == '':
self.data[i]['torrent_name'] = '?'
# self.data[i]['seeder'] = -1
# self.data[i]['leecher'] = -1
self.data[i]['num_files'] = int(info.get('num_files', 0))
self.data[i]['date'] = info.get('creation date', 0)
self.data[i]['tracker'] = info.get('announce', '')
self.data[i]['leecher'] = self.data[i].get('leecher', 0)
self.data[i]['seeder'] = self.data[i].get('seeder', 0)
def OnDeleteTorrent(self, event=None):
selected = self.getSelectedItems()
j = 0
for i in selected:
infohash = self.data[i-j]['infohash']
self.torrent_db.deleteTorrent(infohash, True)
self.DeleteItem(i-j)
self.data.pop(i-j)
j += 1
self.torrent_db.sync()
def OnRightClick(self, event=None):
if not hasattr(self, "deleteTorrentID"):
self.deleteTorrentID = wx.NewId()
self.Bind(wx.EVT_MENU, self.OnDeleteTorrent, id=self.deleteTorrentID)
if not hasattr(self, "downloadTorrentID"):
self.downloadTorrentID = wx.NewId()
self.Bind(wx.EVT_MENU, self.OnDownload, id=self.downloadTorrentID)
# menu for change torrent's rank
sm = wx.Menu()
sm.Append(self.deleteTorrentID, self.utility.lang.get('delete'))
sm.Append(self.downloadTorrentID, self.utility.lang.get('download'))
self.PopupMenu(sm, event.GetPosition())
sm.Destroy()
def OnActivated(self, event):
self.curr_idx = event.m_itemIndex
self.download(self.curr_idx)
def OnDownload(self, event):
first_idx = self.GetFirstSelected()
if first_idx < 0:
return
self.download(first_idx)
while 1:
idx = self.GetNextSelected(first_idx)
if idx < 0:
break
self.download(idx)
def download(self, idx):
src = os.path.join(self.data[idx]['torrent_dir'],
self.data[idx]['torrent_name'])
if os.path.isfile(src):
if self.data[idx]['content_name']:
name = self.data[idx]['content_name']
else:
name = showInfoHash(self.data[idx]['infohash'])
#start_download = self.utility.lang.get('start_downloading')
#str = name + "?"
str = self.utility.lang.get('download_start') + u' ' + name + u'?'
dlg = wx.MessageDialog(self, str, self.utility.lang.get('click_and_download'),
wx.YES_NO|wx.NO_DEFAULT|wx.ICON_INFORMATION)
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_YES:
src = os.path.join(self.data[idx]['torrent_dir'],
self.data[idx]['torrent_name'])
if os.path.isfile(src):
self.parent.clickAndDownload(src)
self.DeleteItem(idx)
del self.data[idx]
self.parent.frame.updateMyPref()
def setRelevanceThreshold(self,value):
self.relevance_threshold = value
def getRelevanceThreshold(self):
return self.relevance_threshold
def loadRelevanceThreshold(self):
self.relevance_threshold = self.parent.utility.config.Read("rec_relevance_threshold", "int" )
def saveRelevanceThreshold(self):
self.parent.utility.config.Write( "rec_relevance_threshold", self.relevance_threshold)
self.parent.utility.config.Flush()
class FilePanel(wx.Panel):
def __init__(self, frame, parent):
self.parent = parent
self.frame = frame
self.utility = frame.utility
self.mypref_db = frame.mypref_db
self.torrent_db = frame.torrent_db
wx.Panel.__init__(self, parent, -1)
mainbox = wx.BoxSizer(wx.VERTICAL)
# Arno: Somehow the list gets painted over the other controls below it in
# the window if we specifiy a size of the list, so don't.
self.list=FileList(self)
mainbox.Add(self.list, 1, wx.EXPAND|wx.ALL, 5)
botbox = self.createBotUtility()
mainbox.Add(botbox, 0, wx.EXPAND|wx.ALL, 5)
self.SetSizer(mainbox)
self.SetAutoLayout(True)
self.Show(True)
self.Bind(masked.EVT_NUM, self.OnSetRelevanceThreshold, self.relev_ctl)
def createBotUtility(self):
botbox = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(self, -1, self.utility.lang.get('recommendinstructions'))
botbox.Add(label, 0, wx.EXPAND|wx.ALL, 5)
relev_box = wx.BoxSizer(wx.HORIZONTAL)
relev_box.Add(wx.StaticText(self, -1, self.utility.lang.get('recommendfilter')), 0, wx.ALIGN_CENTER_VERTICAL)
self.relev_ctl = self.utility.makeNumCtrl(self, self.list.getRelevanceThreshold()/relevance_display_factor, min = 0.0, max = 65536.0, fractionWidth = 2)
relev_box.Add(self.relev_ctl, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 5)
relev_box.Add(wx.StaticText(self, -1, self.utility.lang.get('recommendfilterall')), 0, wx.ALIGN_CENTER_VERTICAL)
botbox.Add(relev_box, 1, wx.EXPAND|wx.ALL, 5)
return botbox
def updateFileList(self,relevance_threshold=0):
self.list.setRelevanceThreshold(relevance_threshold)
self.list.loadList()
def clickAndDownload(self, src):
self.utility.queue.addtorrents.AddTorrentFromFile(src, forceasklocation = False)
def OnSetRelevanceThreshold(self,event=None):
value = self.relev_ctl.GetValue()
value = int(value * relevance_display_factor)
self.updateFileList(value)
def updateColumns(self, force=False):
self.list.loadList(False, False)
class ABCFileFrame(wx.Frame):
def __init__(self, parent):
self.utility = parent.utility
wx.Frame.__init__(self, None, -1, self.utility.lang.get('tb_file_short'),
size=self.utility.frame.fileFrame_size,
pos=self.utility.frame.fileFrame_pos)
self.main_panel = self.createMainPanel()
self.count = 0
self.loadFileList = False
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.Bind(wx.EVT_IDLE, self.updateFileList)
self.Show()
def createMainPanel(self):
main_panel = wx.Panel(self)
self.createNoteBook(main_panel)
bot_box = self.createBottomBoxer(main_panel)
mainbox = wx.BoxSizer(wx.VERTICAL)
mainbox.Add(self.notebook, 1, wx.EXPAND|wx.ALL, 5)
mainbox.Add(bot_box, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5)
main_panel.SetSizer(mainbox)
return main_panel
def loadDatabase(self):
self.mypref_db = self.utility.mypref_db
self.torrent_db = self.utility.torrent_db
def createNoteBook(self, main_panel):
self.loadDatabase()
self.notebook = wx.Notebook(main_panel, -1)
self.filePanel = FilePanel(self, self.notebook)
self.myPreferencePanel = MyPreferencePanel(self, self.notebook)
self.notebook.AddPage(self.filePanel, self.utility.lang.get('file_list_title'))
self.notebook.AddPage(self.myPreferencePanel, self.utility.lang.get('mypref_list_title'))
def createBottomBoxer(self, main_panel):
bot_box = wx.BoxSizer(wx.HORIZONTAL)
button = wx.Button(main_panel, -1, self.utility.lang.get('close'), style = wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, button)
bot_box.Add(button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 3)
return bot_box
def updateMyPref(self): # used by File List
self.myPreferencePanel.list.loadList()
def updateFileList(self, event=None):
# Arno: on Linux, the list does not get painted properly before this
# idle handler is called, which is weird. Hence, I wait for the next
# idle event and load the filelist there.
self.count += 1
if not self.loadFileList and self.count >= 2:
self.filePanel.list.loadList()
self.Unbind(wx.EVT_IDLE)
self.count = 0
def OnCloseWindow(self, event = None):
self.filePanel.list.saveRelevanceThreshold()
self.utility.frame.fileFrame_size = self.GetSize()
self.utility.frame.fileFrame_pos = self.GetPosition()
self.utility.frame.fileFrame = None
self.utility.abcfileframe = None
self.Destroy()
|