In the "Games" filter, 27_3draw was showing up as 273draw with the 3 underlined....
[fpdb-dooglus.git] / pyfpdb / SplitHandHistory.py
blob80a07407e28c502e98ef9bed9aaf8ee9647100a2
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2010-2011 Chaz Littlejohn
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.
18 import L10n
19 _ = L10n.get_translation()
21 # This code is based heavily on stars-support-hh-split.py by Mika Boström
23 import os
24 import sys
25 import re
26 import codecs
27 import Options
28 import Configuration
29 from Exceptions import *
30 from cStringIO import StringIO
32 (options, argv) = Options.fpdb_options()
34 __ARCHIVE_PRE_HEADER_REGEX='^Hand #(\d+)\s*$|\*{20}\s#\s\d+\s\*+\s+'
35 re_SplitArchive = re.compile(__ARCHIVE_PRE_HEADER_REGEX)
36 codepage = ["utf-16", "utf-8", "cp1252"]
39 class SplitHandHistory:
40 def __init__(self, config, in_path = '-', out_path = None, hands = 100, filter = "PokerStarsToFpdb", archive = False):
41 self.config = config
42 self.in_path = in_path
43 self.out_path = out_path
44 if not self.out_path:
45 self.out_path = os.path.dirname(self.in_path)
46 self.hands = hands
47 self.archive = archive
48 self.re_SplitHands = None
49 self.line_delimiter = None
50 self.line_addendum = None
51 self.filedone = False
53 #Acquire re_SplitHands for this hh
54 filter_name = filter.replace("ToFpdb", "")
55 mod = __import__(filter)
56 obj = getattr(mod, filter_name, None)
57 self.re_SplitHands = obj.re_SplitHands
59 #Determine line delimiter type if any
60 if self.re_SplitHands.match('\n\n'):
61 self.line_delimiter = '\n\n'
62 if self.re_SplitHands.match('\n\n\n'):
63 self.line_delimiter = '\n\n\n'
65 #Add new line addendum for sites which match SplitHand to next line as well
66 if filter_name == 'OnGame':
67 self.line_addendum = '*'
68 if filter_name == 'Carbon':
69 self.line_addendum = '<game'
71 #Open the gargantuan file
72 for kodec in self.__listof(codepage):
73 try:
74 infile = codecs.open(self.in_path, 'r', kodec)
75 except IOError:
76 print (_('File not found'))
77 sys.exit(2)
79 #Split with do_hands_per_file if archive and paragraphs if a regular hh
80 if self.archive:
81 nn = 0
82 while True:
83 nn += 1
84 check = self.do_hands_per_file(infile, nn)
85 if check is None:
86 print (_('%s processed') % self.in_path)
87 break
88 else:
89 filenum = 0
90 while not self.filedone:
91 filenum += 1
92 outfile = self.new_file(filenum)
93 handnum = 0
94 for hand in self.paragraphs(infile, None, self.line_addendum):
95 outfile.write(hand)
96 if self.line_delimiter:
97 outfile.write(self.line_delimiter)
98 handnum += 1
99 if handnum >= self.hands:
100 break
101 outfile.close()
103 def new_file(self, fileno=-1):
104 if fileno < 1:
105 print (_('Nope, will not work (fileno=%d)') % fileno)
106 sys.exit(2)
107 basename = os.path.splitext(os.path.basename(self.in_path))[0]
108 name = os.path.join(self.out_path, basename+'-%06d.txt' % fileno)
109 print ('-> %s' % name)
110 newfile = file(name, 'w')
111 return newfile
113 #Archive Hand Splitter
114 def do_hands_per_file(self, infile, num=-1):
115 done = False
116 n = 0
117 outfile = self.new_file(num)
118 while n < self.hands:
119 try:
120 infile = self.next_hand(infile)
121 infile = self.process_hand(infile, outfile)
122 except FpdbEndOfFile:
123 done = True
124 break
125 except:
126 print _("Unexpected error processing file")
127 sys.exit(2)
128 n += 1
129 outfile.close()
130 if not done:
131 return infile
132 else:
133 return None
135 #Non-Archive Hand Splitter
136 def paragraphs(self, file, separator=None, addendum=None):
137 if not callable(separator) and self.line_delimiter:
138 def separator(line): return line == '\n'
139 else:
140 def separator(line): return self.re_SplitHands.search(line)
141 file_str = StringIO()
142 print file_str.getvalue()
143 for line in file:
144 if separator(line+addendum):
145 if file_str.getvalue():
146 if not self.line_delimiter:
147 file_str.write(line)
148 yield file_str.getvalue()
149 file_str = None
150 file_str = StringIO()
151 else:
152 file_str.write(line)
153 if file_str.getvalue(): yield file_str.getvalue()
154 self.filedone = True
157 # Finds pre-hand header (Hand #<num>)
158 def next_hand(self, infile):
159 m = None
160 while not m:
161 l = infile.readline()
162 #print l, len(l)
163 # Catch EOF
164 if len(l) == 0:
165 raise FpdbEndOfFile(_("End of file reached"))
166 m = re_SplitArchive.search(l)
167 # There is an empty line after pre-hand header and actual HH entry
168 l = infile.readline()
170 return infile
172 # Each individual hand is written separately
173 def process_hand(self, infile=None, outfile=None):
174 l = infile.readline()
175 l = l.replace('\r\n', '\n')
176 outfile.write(l)
177 l = infile.readline()
179 while len(l) < 3:
180 l = infile.readline()
182 while len(l) > 2:
183 l = l.replace('\r\n', '\n')
184 outfile.write(l)
185 l = infile.readline()
186 outfile.write(self.line_delimiter)
187 return infile
189 def __listof(self, x):
190 if isinstance(x, list) or isinstance(x, tuple):
191 return x
192 else:
193 return [x]
195 def main(argv=None):
196 if argv is None:
197 argv = sys.argv[1:]
199 if not options.config:
200 options.config = Configuration.Config(file = "HUD_config.test.xml")
202 if options.filename:
203 SplitHH = SplitHandHistory(options.config, options.filename, options.outpath, options.hands,
204 options.hhc, options.archive)
206 if __name__ == '__main__':
207 sys.exit(main())