2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Carl Gherardi
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
9 #This program is distributed in the hope that it will be useful,
10 #but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 #GNU General Public License for more details.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
19 _
= L10n
.get_translation()
21 from decimal_wrapper
import Decimal
23 from BeautifulSoup
import BeautifulSoup
25 from Exceptions
import FpdbParseError
26 from HandHistoryConverter
import *
28 from TourneySummary
import *
31 class MergeSummary(TourneySummary
):
32 limits
= { 'No Limit':'nl', 'No Limit ':'nl', 'Fixed Limit':'fl', 'Limit':'fl', 'Pot Limit':'pl', 'Pot Limit ':'pl', 'Half Pot Limit':'hp'}
33 games
= { # base, category
34 'Holdem' : ('hold','holdem'),
35 'Holdem Tournament' : ('hold','holdem'),
36 'Omaha' : ('hold','omahahi'),
37 'Omaha Tournament' : ('hold','omahahi'),
38 'Omaha H/L8' : ('hold','omahahilo'),
39 '2-7 Lowball' : ('draw','27_3draw'),
40 'A-5 Lowball' : ('draw','a5_3draw'),
41 'Badugi' : ('draw','badugi'),
42 '5-Draw w/Joker' : ('draw','fivedraw'),
43 '5-Draw' : ('draw','fivedraw'),
44 '7-Stud' : ('stud','studhi'),
45 '7-Stud H/L8' : ('stud','studhilo'),
46 '5-Stud' : ('stud','5studhi'),
47 'Razz' : ('stud','razz')
50 'Texas Holdem' : ('hold','holdem'),
51 'Omaha' : ('hold','omahahi'),
52 'Omaha HiLo' : ('hold','omahahilo'),
53 '2-7 Low Triple Draw' : ('draw','27_3draw'),
54 'Badugi' : ('draw','badugi'),
55 'Seven Card Stud' : ('stud','studhi'),
56 'Seven Card Stud HiLo' : ('stud','studhilo'),
57 'Five Card Stud' : ('stud','studhilo'),
58 'Razz' : ('stud','razz')
61 months
= { 'January':1, 'Jan':1, 'February':2, 'Feb':2, 'March':3, 'Mar':3,
62 'April':4, 'Apr':4, 'May':5, 'May':5, 'June':6, 'Jun':6,
63 'July':7, 'Jul':7, 'August':8, 'Aug':8, 'September':9, 'Sep':9,
64 'October':10, 'Oct':10, 'November':11, 'Nov':11, 'December':12, 'Dec':12}
68 'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
69 'LS' : u
"\$|\xe2\x82\xac|\u20ac|" # legal currency symbols
71 re_GameTypeHH
= re
.compile(r
'<description type="(?P<GAME>Holdem|Omaha|Omaha|Omaha\sH/L8|2\-7\sLowball|A\-5\sLowball|Badugi|5\-Draw\sw/Joker|5\-Draw|7\-Stud|7\-Stud\sH/L8|5\-Stud|Razz|HORSE)(?P<TYPE>\sTournament)?" stakes="(?P<LIMIT>[a-zA-Z ]+)(\s\(?\$?(?P<SB>[.0-9]+)?/?\$?(?P<BB>[.0-9]+)?(?P<blah>.*)\)?)?"/>', re
.MULTILINE
)
72 re_HandInfoHH
= re
.compile(r
'<game id="(?P<HID1>[0-9]+)-(?P<HID2>[0-9]+)" starttime="(?P<DATETIME>[0-9]+)" numholecards="[0-9]+" gametype="[0-9]+" (multigametype="(?P<MULTIGAMETYPE>\d+)" )?(seats="(?P<SEATS>[0-9]+)" )?realmoney="(?P<REALMONEY>(true|false))" data="[0-9]+\|(?P<TABLENAME>[^|]+)\|(?P<TDATA>[^|]+)\|?.*>', re
.MULTILINE
)
74 re_HTMLName
= re
.compile("Name</th><td>(?P<NAME>.+?)</td>")
75 re_HTMLGameType
= re
.compile("""Game Type</th><td>(?P<LIMIT>Fixed Limit|No Limit|Pot Limit) (?P<GAME>Texas\sHoldem|Omaha|Omaha\sHiLo|2\-7\sLow\sTriple\sDraw|Badugi|Seven\sCard\sStud|Seven\sCard\sStud\sHiLo|Five\sCard\sStud|Razz|HORSE|HA|HO)</td>""")
76 re_HTMLBuyIn
= re
.compile("Buy In</th><td>(?P<BUYIN>[0-9,.]+)</td>")
77 re_HTMLFee
= re
.compile("Entry Fee</th><td>(?P<FEE>[0-9,.]+)</td>")
78 re_HTMLBounty
= re
.compile("Bounty</th><td>(?P<KOBOUNTY>.+?)</td>")
79 re_HTMLAddons
= re
.compile("Addons</th><td>(?P<ADDON>.+?)</td>")
80 re_HTMLRebuy
= re
.compile("Rebuys</th><td>(?P<REBUY>.+?)</td>")
81 re_HTMLTourNo
= re
.compile("Game ID</th><td>(?P<TOURNO>[0-9]+)-1</td>")
82 re_HTMLPlayer
= re
.compile(u
"""<tr><td align="center">(?P<RANK>\d+)</td><td>(?P<PNAME>.+?)</td><td>(?P<WINNINGS>.+?)</td></tr>""")
83 re_HTMLDetails
= re
.compile(u
"""<p class="text">(?P<LABEL>.+?) : (?P<VALUE>.+?)</p>""")
84 re_HTMLPrizepool
= re
.compile(u
"""Total Prizepool</th><td>(?P<PRIZEPOOL>[0-9,.]+)</td>""")
85 re_HTMLStartTime
= re
.compile("Start Time</th><td>(?P<STARTTIME>.+?)</td>")
86 re_HTMLDateTime
= re
.compile("\w+?\s+?(?P<D>\d+)\w+?\s+(?P<M>\w+)\s+(?P<Y>\d+),?\s+(?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+)")
88 re_Ticket
= re
.compile(u
""" / Ticket (?P<VALUE>[0-9.]+)€""")
93 def getSplitRe(self
, head
):
94 re_SplitTourneys
= re
.compile("PokerStars Tournament ")
95 return re_SplitTourneys
97 def parseSummary(self
):
98 # id type of file and call correct function
99 m
= self
.re_GameTypeHH
.search(self
.summaryText
)
102 if ' Tournament' == mg
['TYPE']:
103 self
.parseSummaryFromHH(mg
)
105 self
.parseSummaryFile()
107 def parseSummaryFromHH(self
, mg
):
109 self
.gametype
['limitType'] = self
.limits
[mg
['LIMIT']]
111 if mg
['GAME'] == "HORSE":
112 log
.error(_("MergeSummary.determineGameType: HORSE found, unsupported"))
114 #(self.info['base'], self.info['category']) = self.Multigametypes[m2.group('MULTIGAMETYPE')]
116 self
.gametype
['category'] = self
.games
[mg
['GAME']][1]
117 m
= self
.re_HandInfoHH
.search(self
.summaryText
)
119 tmp
= self
.summaryText
[0:200]
120 log
.error(_("MergeSummary.readHandInfo: '%s'") % tmp
)
123 tourneyNameFull
= m
.group('TABLENAME')
124 self
.tourneyName
= m
.group('TABLENAME')[:40]
125 self
.tourNo
= re
.split('-', m
.group('TDATA'))[0]
126 self
.startTime
= datetime
.datetime
.strptime(m
.group('DATETIME')[:12],'%Y%m%d%H%M')
127 self
.startTime
= HandHistoryConverter
.changeTimezone(self
.startTime
, "ET", "UTC")
128 obj
= getattr(MergeToFpdb
, "Merge", None)
129 hhc
= obj(self
.config
, in_path
= self
.in_path
, sitename
= None, autostart
= False)
131 if tourneyNameFull
not in hhc
.SnG_Structures
:
132 log
.error(_("MergeSummary.determineGameType: No match in SnG_Structures"))
135 self
.buyin
= int(100*hhc
.SnG_Structures
[tourneyNameFull
]['buyIn'])
136 self
.fee
= int(100*hhc
.SnG_Structures
[tourneyNameFull
]['fee'])
137 self
.entries
= hhc
.SnG_Structures
[tourneyNameFull
]['seats']
138 self
.buyinCurrency
= hhc
.SnG_Structures
[tourneyNameFull
]['currency']
139 self
.currency
= hhc
.SnG_Structures
[tourneyNameFull
]['payoutCurrency']
140 self
.maxseats
= hhc
.SnG_Structures
[tourneyNameFull
]['seats']
141 self
.prizepool
= sum(hhc
.SnG_Structures
[tourneyNameFull
]['payouts'])
142 payouts
= len(hhc
.SnG_Structures
[tourneyNameFull
]['payouts'])
145 if hhc
.SnG_Structures
[tourneyNameFull
]['multi']:
146 log
.error(_("MergeSummary.determineGameType: Muli-table SnG found, unsupported"))
149 handsList
= hhc
.allHandsAsList()
150 for handText
in handsList
:
151 players
, out
, won
= {}, [], []
152 for m
in hhc
.re_PlayerOut
.finditer(handText
):
153 out
.append(m
.group('PSEAT'))
155 for m
in hhc
.re_PlayerInfo
.finditer(handText
):
156 players
[m
.group('SEAT')] = m
.group('PNAME')
157 if not players
: continue
158 for m
in hhc
.re_CollectPot
.finditer(handText
):
159 won
.append(m
.group('PSEAT'))
165 winnings
= int(100*hhc
.SnG_Structures
[tourneyNameFull
]['payouts'][0])
167 rank
= len(players
) - i
169 winnings
= int(100*hhc
.SnG_Structures
[tourneyNameFull
]['payouts'][rank
-1])
171 self
.addPlayer(rank
, players
[n
], winnings
, self
.currency
, 0, 0, 0)
173 def parseSummaryFile(self
):
174 self
.buyinCurrency
= "USD"
175 soup
= BeautifulSoup(self
.summaryText
)
176 tables
= soup
.findAll('table')
177 table1
= BeautifulSoup(str(tables
[0])).findAll('tr')
178 table2
= BeautifulSoup(str(tables
[1])).findAll('tr')
179 # FIXME: Searching every line for all regexes is pretty horrible
180 # FIXME: Need to search for 'Status: Finished'
183 m
= self
.re_HTMLGameType
.search(str(p
))
185 #print "DEBUG: re_HTMLGameType: '%s' '%s'" %(m.group('LIMIT'), m.group('GAME'))
186 if m
.group('GAME') in ("HORSE", "HA", "HO"):
187 log
.error(_("MergeSummary.parseSummaryFile: %s found, unsupported") % m
.group('GAME'))
189 self
.gametype
['limitType'] = self
.limits
[m
.group('LIMIT')]
190 self
.gametype
['category'] = self
.games_html
[m
.group('GAME')][1]
191 m
= self
.re_HTMLTourNo
.search(str(p
))
193 #print "DEBUG: re_HTMLTourNo: '%s'" % m.group('TOURNO')
194 self
.tourNo
= m
.group('TOURNO')
195 m
= self
.re_HTMLName
.search(str(p
))
197 #print "DEBUG: re_HTMLName: '%s'" % m.group('NAME')
198 self
.tourneyName
= m
.group('NAME')[:40]
199 if m
.group('NAME').find("$")!=-1:
200 self
.buyinCurrency
="USD"
201 elif m
.group('NAME').find(u
"€")!=-1:
202 self
.buyinCurrency
="EUR"
203 m
= self
.re_HTMLPrizepool
.search(str(p
))
205 #print "DEBUG: re_HTMLPrizepool: '%s'" % m.group('PRIZEPOOL')
206 self
.prizepool
= int(convert_to_decimal(m
.group('PRIZEPOOL')))
207 m
= self
.re_HTMLBuyIn
.search(str(p
))
209 #print "DEBUG: re_HTMLBuyIn: '%s'" % m.group('BUYIN')
210 self
.buyin
= int(100*convert_to_decimal(m
.group('BUYIN')))
212 self
.buyinCurrency
="FREE"
213 m
= self
.re_HTMLFee
.search(str(p
))
215 #print "DEBUG: re_HTMLFee: '%s'" % m.group('FEE')
216 self
.fee
= int(100*convert_to_decimal(m
.group('FEE')))
217 m
= self
.re_HTMLBounty
.search(str(p
))
219 #print "DEBUG: re_HTMLBounty: '%s'" % m.group('KOBOUNTY')
220 if m
.group('KOBOUNTY') != '0.00':
222 self
.koBounty
= int(100*convert_to_decimal(m
.group('KOBOUNTY')))
223 m
= self
.re_HTMLAddons
.search(str(p
))
225 #print "DEBUG: re_HTMLAddons: '%s'" % m.group('ADDON')
226 if m
.group('ADDON') != '0':
228 self
.addOnCost
= self
.buyin
229 m
= self
.re_HTMLRebuy
.search(str(p
))
231 #print "DEBUG: re_HTMLRebuy: '%s'" % m.group('REBUY')
232 if m
.group('REBUY') != '0':
234 self
.rebuyCost
= self
.buyin
235 m
= self
.re_HTMLStartTime
.search(str(p
))
237 m2
= self
.re_HTMLDateTime
.search(m
.group('STARTTIME'))
239 month
= self
.months
[m2
.group('M')]
240 datetimestr
= "%s/%s/%s %s:%s:%s" % (m2
.group('Y'), month
,m2
.group('D'),m2
.group('H'),m2
.group('MIN'),m2
.group('S'))
241 self
.startTime
= datetime
.datetime
.strptime(datetimestr
, "%Y/%m/%d %H:%M:%S")
242 self
.startTime
= HandHistoryConverter
.changeTimezone(self
.startTime
, "ET", "UTC")
244 self
.currency
= self
.buyinCurrency
246 m
= self
.re_HTMLPlayer
.search(str(p
))
249 #print "DEBUG: rank: %s pname: %s won: %s" %(m.group('RANK'), m.group('PNAME'), m.group('WINNINGS'))
255 rank
= int(m
.group('RANK'))
256 name
= m
.group('PNAME')
257 if m
.group('WINNINGS') != None:
258 if m
.group('WINNINGS').find("$")!=-1:
260 elif m
.group('WINNINGS').find(u
"€")!=-1:
262 winnings
= int(100*convert_to_decimal(m
.group('WINNINGS')))
263 self
.addPlayer(rank
, name
, winnings
, self
.currency
, rebuyCount
, addOnCount
, koCount
)
265 def convert_to_decimal(string
):
266 dec
= string
.strip(u
'€€\u20ac$')
267 dec
= dec
.replace(u
',','.')
268 dec
= dec
.replace(u
' ','')