10
10
from pytr .api import TradeRepublicError
11
11
from pytr .timeline import Timeline
12
12
13
+
13
14
class DL :
14
15
def __init__ (
15
16
self ,
16
17
tr ,
17
18
output_path ,
18
19
filename_fmt ,
19
20
since_timestamp = 0 ,
20
- history_file = ' pytr_history' ,
21
+ history_file = " pytr_history" ,
21
22
max_workers = 8 ,
22
23
universal_filepath = False ,
23
- sort_export = False
24
+ sort_export = False ,
24
25
):
25
- '''
26
+ """
26
27
tr: api object
27
28
output_path: name of the directory where the downloaded files are saved
28
29
filename_fmt: format string to customize the file names
29
30
since_timestamp: downloaded files since this date (unix timestamp)
30
- '''
31
+ """
31
32
self .tr = tr
32
33
self .output_path = Path (output_path )
33
34
self .history_file = self .output_path / history_file
@@ -36,7 +37,9 @@ def __init__(
36
37
self .universal_filepath = universal_filepath
37
38
self .sort_export = sort_export
38
39
39
- self .session = FuturesSession (max_workers = max_workers , session = self .tr ._websession )
40
+ self .session = FuturesSession (
41
+ max_workers = max_workers , session = self .tr ._websession
42
+ )
40
43
self .futures = []
41
44
42
45
self .docs_request = 0
@@ -49,115 +52,130 @@ def __init__(
49
52
self .load_history ()
50
53
51
54
def load_history (self ):
52
- '''
55
+ """
53
56
Read history file with URLs if it exists, otherwise create empty file
54
- '''
57
+ """
55
58
if self .history_file .exists ():
56
59
with self .history_file .open () as f :
57
60
self .doc_urls_history = f .read ().splitlines ()
58
- self .log .info (f' Found { len (self .doc_urls_history )} lines in history file' )
61
+ self .log .info (f" Found { len (self .doc_urls_history )} lines in history file" )
59
62
else :
60
63
self .history_file .parent .mkdir (exist_ok = True , parents = True )
61
64
self .history_file .touch ()
62
- self .log .info (' Created history file' )
65
+ self .log .info (" Created history file" )
63
66
64
67
async def dl_loop (self ):
65
68
await self .tl .get_next_timeline_transactions ()
66
69
67
70
while True :
68
71
try :
69
- _subscription_id , subscription , response = await self .tr .recv ()
72
+ _ , subscription , response = await self .tr .recv ()
70
73
except TradeRepublicError as e :
71
74
self .log .fatal (str (e ))
72
75
73
- if subscription [ ' type' ] == ' timelineTransactions' :
76
+ if subscription . get ( " type" , "" ) == " timelineTransactions" :
74
77
await self .tl .get_next_timeline_transactions (response )
75
- elif subscription [ ' type' ] == ' timelineActivityLog' :
78
+ elif subscription . get ( " type" , "" ) == " timelineActivityLog" :
76
79
await self .tl .get_next_timeline_activity_log (response )
77
- elif subscription [ ' type' ] == ' timelineDetailV2' :
80
+ elif subscription . get ( " type" , "" ) == " timelineDetailV2" :
78
81
await self .tl .process_timelineDetail (response , self )
79
82
else :
80
- self .log .warning (f"unmatched subscription of type '{ subscription ['type' ]} ':\n { preview (response )} " )
83
+ self .log .warning (
84
+ f"unmatched subscription of type '{ subscription ['type' ]} ':\n { preview (response )} "
85
+ )
81
86
82
87
def dl_doc (self , doc , titleText , subtitleText , subfolder = None ):
83
- '''
88
+ """
84
89
send asynchronous request, append future with filepath to self.futures
85
- '''
86
- doc_url = doc [' action' ][ ' payload' ]
90
+ """
91
+ doc_url = doc [" action" ][ " payload" ]
87
92
if subtitleText is None :
88
- subtitleText = ''
93
+ subtitleText = ""
89
94
90
95
try :
91
- date = doc [' detail' ]
92
- iso_date = '-' .join (date .split ('.' )[::- 1 ])
96
+ date = doc [" detail" ]
97
+ iso_date = "-" .join (date .split ("." )[::- 1 ])
93
98
except KeyError :
94
- date = ''
95
- iso_date = ''
96
- doc_id = doc ['id' ]
99
+ date = ""
100
+ iso_date = ""
101
+ doc_id = doc ["id" ]
97
102
98
103
# extract time from subtitleText
99
104
try :
100
- time = re .findall (' um (\\ d+:\\ d+) Uhr' , subtitleText )
105
+ time = re .findall (" um (\\ d+:\\ d+) Uhr" , subtitleText )
101
106
if time == []:
102
- time = ''
107
+ time = ""
103
108
else :
104
- time = f' { time [0 ]} '
109
+ time = f" { time [0 ]} "
105
110
except TypeError :
106
- time = ''
111
+ time = ""
107
112
108
113
if subfolder is not None :
109
114
directory = self .output_path / subfolder
110
115
else :
111
116
directory = self .output_path
112
117
113
118
# If doc_type is something like 'Kosteninformation 2', then strip the 2 and save it in doc_type_num
114
- doc_type = doc [' title' ].rsplit (' ' )
119
+ doc_type = doc [" title" ].rsplit (" " )
115
120
if doc_type [- 1 ].isnumeric () is True :
116
- doc_type_num = f' { doc_type .pop ()} '
121
+ doc_type_num = f" { doc_type .pop ()} "
117
122
else :
118
- doc_type_num = ''
123
+ doc_type_num = ""
119
124
120
- doc_type = ' ' .join (doc_type )
121
- titleText = titleText .replace (' \n ' , '' ).replace ('/' , '-' )
122
- subtitleText = subtitleText .replace (' \n ' , '' ).replace ('/' , '-' )
125
+ doc_type = " " .join (doc_type )
126
+ titleText = titleText .replace (" \n " , "" ).replace ("/" , "-" )
127
+ subtitleText = subtitleText .replace (" \n " , "" ).replace ("/" , "-" )
123
128
124
129
filename = self .filename_fmt .format (
125
- iso_date = iso_date , time = time , title = titleText , subtitle = subtitleText , doc_num = doc_type_num , id = doc_id
130
+ iso_date = iso_date ,
131
+ time = time ,
132
+ title = titleText ,
133
+ subtitle = subtitleText ,
134
+ doc_num = doc_type_num ,
135
+ id = doc_id ,
126
136
)
127
137
128
- filename_with_doc_id = filename + f' ({ doc_id } )'
138
+ filename_with_doc_id = filename + f" ({ doc_id } )"
129
139
130
- if doc_type in ['Kontoauszug' , 'Depotauszug' ]:
131
- filepath = directory / 'Abschlüsse' / f'{ filename } ' / f'{ doc_type } .pdf'
132
- filepath_with_doc_id = directory / 'Abschlüsse' / f'{ filename_with_doc_id } ' / f'{ doc_type } .pdf'
140
+ if doc_type in ["Kontoauszug" , "Depotauszug" ]:
141
+ filepath = directory / "Abschlüsse" / f"{ filename } " / f"{ doc_type } .pdf"
142
+ filepath_with_doc_id = (
143
+ directory / "Abschlüsse" / f"{ filename_with_doc_id } " / f"{ doc_type } .pdf"
144
+ )
133
145
else :
134
- filepath = directory / doc_type / f' { filename } .pdf'
135
- filepath_with_doc_id = directory / doc_type / f' { filename_with_doc_id } .pdf'
146
+ filepath = directory / doc_type / f" { filename } .pdf"
147
+ filepath_with_doc_id = directory / doc_type / f" { filename_with_doc_id } .pdf"
136
148
137
149
if self .universal_filepath :
138
- filepath = sanitize_filepath (filepath , '_' , 'universal' )
139
- filepath_with_doc_id = sanitize_filepath (filepath_with_doc_id , '_' , 'universal' )
150
+ filepath = sanitize_filepath (filepath , "_" , "universal" )
151
+ filepath_with_doc_id = sanitize_filepath (
152
+ filepath_with_doc_id , "_" , "universal"
153
+ )
140
154
else :
141
- filepath = sanitize_filepath (filepath , '_' , ' auto' )
142
- filepath_with_doc_id = sanitize_filepath (filepath_with_doc_id , '_' , ' auto' )
155
+ filepath = sanitize_filepath (filepath , "_" , " auto" )
156
+ filepath_with_doc_id = sanitize_filepath (filepath_with_doc_id , "_" , " auto" )
143
157
144
158
if filepath in self .filepaths :
145
- self .log .debug (f'File { filepath } already in queue. Append document id { doc_id } ...' )
159
+ self .log .debug (
160
+ f"File { filepath } already in queue. Append document id { doc_id } ..."
161
+ )
146
162
if filepath_with_doc_id in self .filepaths :
147
- self .log .debug (f'File { filepath_with_doc_id } already in queue. Skipping...' )
163
+ self .log .debug (
164
+ f"File { filepath_with_doc_id } already in queue. Skipping..."
165
+ )
148
166
return
149
167
else :
150
168
filepath = filepath_with_doc_id
151
- doc [' local filepath' ] = str (filepath )
169
+ doc [" local filepath" ] = str (filepath )
152
170
self .filepaths .append (filepath )
153
171
154
172
if filepath .is_file () is False :
155
- doc_url_base = doc_url .split ('?' )[0 ]
173
+ doc_url_base = doc_url .split ("?" )[0 ]
156
174
if doc_url_base in self .doc_urls :
157
- self .log .debug (f' URL { doc_url_base } already in queue. Skipping...' )
175
+ self .log .debug (f" URL { doc_url_base } already in queue. Skipping..." )
158
176
return
159
177
elif doc_url_base in self .doc_urls_history :
160
- self .log .debug (f' URL { doc_url_base } already in history. Skipping...' )
178
+ self .log .debug (f" URL { doc_url_base } already in history. Skipping..." )
161
179
return
162
180
else :
163
181
self .doc_urls .append (doc_url_base )
@@ -166,37 +184,39 @@ def dl_doc(self, doc, titleText, subtitleText, subfolder=None):
166
184
future .filepath = filepath
167
185
future .doc_url_base = doc_url_base
168
186
self .futures .append (future )
169
- self .log .debug (f' Added { filepath } to queue' )
187
+ self .log .debug (f" Added { filepath } to queue" )
170
188
else :
171
- self .log .debug (f' file { filepath } already exists. Skipping...' )
189
+ self .log .debug (f" file { filepath } already exists. Skipping..." )
172
190
173
191
def work_responses (self ):
174
- '''
192
+ """
175
193
process responses of async requests
176
- '''
194
+ """
177
195
if len (self .doc_urls ) == 0 :
178
- self .log .info (' Nothing to download' )
196
+ self .log .info (" Nothing to download" )
179
197
exit (0 )
180
198
181
- with self .history_file .open ('a' ) as history_file :
182
- self .log .info (' Waiting for downloads to complete..' )
199
+ with self .history_file .open ("a" ) as history_file :
200
+ self .log .info (" Waiting for downloads to complete.." )
183
201
for future in as_completed (self .futures ):
184
202
if future .filepath .is_file () is True :
185
- self .log .debug (f' file { future .filepath } was already downloaded.' )
203
+ self .log .debug (f" file { future .filepath } was already downloaded." )
186
204
187
205
try :
188
206
r = future .result ()
189
207
except Exception as e :
190
208
self .log .fatal (str (e ))
191
209
192
210
future .filepath .parent .mkdir (parents = True , exist_ok = True )
193
- with open (future .filepath , 'wb' ) as f :
211
+ with open (future .filepath , "wb" ) as f :
194
212
f .write (r .content )
195
213
self .done += 1
196
- history_file .write (f' { future .doc_url_base } \n ' )
214
+ history_file .write (f" { future .doc_url_base } \n " )
197
215
198
- self .log .debug (f'{ self .done :>3} /{ len (self .doc_urls )} { future .filepath .name } ' )
216
+ self .log .debug (
217
+ f"{ self .done :>3} /{ len (self .doc_urls )} { future .filepath .name } "
218
+ )
199
219
200
220
if self .done == len (self .doc_urls ):
201
- self .log .info (' Done.' )
221
+ self .log .info (" Done." )
202
222
exit (0 )
0 commit comments