epstein-files 1.1.2__py3-none-any.whl → 1.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import json
3
3
  from rich.padding import Padding
4
4
 
5
5
  from epstein_files.documents.document import Document
6
- from epstein_files.documents.email import JUNK_EMAILERS, KRASSNER_RECIPIENTS, Email
6
+ from epstein_files.documents.email import KRASSNER_RECIPIENTS, Email
7
7
  from epstein_files.documents.messenger_log import MessengerLog
8
8
  from epstein_files.documents.other_file import FIRST_FEW_LINES, OtherFile
9
9
  from epstein_files.epstein_files import EpsteinFiles, count_by_month
@@ -11,20 +11,24 @@ from epstein_files.util.constant import output_files
11
11
  from epstein_files.util.constant.html import *
12
12
  from epstein_files.util.constant.names import *
13
13
  from epstein_files.util.constant.output_files import JSON_FILES_JSON_PATH, JSON_METADATA_PATH
14
- from epstein_files.util.constant.strings import TIMESTAMP_DIM, TIMESTAMP_STYLE
14
+ from epstein_files.util.constant.strings import DEFAULT_NAME_STYLE, TIMESTAMP_DIM, TIMESTAMP_STYLE
15
15
  from epstein_files.util.data import dict_sets_to_lists, sort_dict
16
16
  from epstein_files.util.env import args
17
17
  from epstein_files.util.file_helper import log_file_write
18
+ from epstein_files.util.highlighted_group import (JUNK_EMAILERS, QUESTION_MARKS_TXT, get_category_txt_for_name,
19
+ get_info_for_name, get_style_for_name, styled_name)
18
20
  from epstein_files.util.logging import logger
19
21
  from epstein_files.util.rich import *
20
22
 
23
+ OTHER_INTERESTING_EMAILS_SUBTITLE = 'Other Interesting Emails\n(these emails have been flagged as being of particular interest)'
21
24
  PRINT_COLOR_KEY_EVERY_N_EMAILS = 150
25
+ ALT_INFO_STYLE = 'medium_purple4'
22
26
 
23
27
  # Order matters. Default names to print emails for.
24
28
  DEFAULT_EMAILERS = [
25
29
  JEREMY_RUBIN,
26
- JOI_ITO,
27
30
  JABOR_Y,
31
+ JOI_ITO,
28
32
  STEVEN_SINOFSKY,
29
33
  AL_SECKEL,
30
34
  DANIEL_SIAD,
@@ -43,6 +47,18 @@ DEFAULT_EMAILERS = [
43
47
  JENNIFER_JACQUET,
44
48
  ZUBAIR_KHAN,
45
49
  None,
50
+ JEFFREY_EPSTEIN,
51
+ ]
52
+
53
+ INTERESTING_EMAIL_IDS = [
54
+ '032229', # Michael Wolff on strategy
55
+ '028784', # seminars: Money / Power
56
+ '029342', # Hakeem Jeffries
57
+ '023454', # Email invitation sent to tech CEOs + Epstein
58
+ '030630', # 'What happens with zubair's project?'
59
+ '033178', # 'How is it going with Zubair?'
60
+ '022396', # Ukraine friend
61
+ # '023627', # Michael Wolff article (already printed bc epstein->epstein email)
46
62
  ]
47
63
 
48
64
  INVALID_FOR_EPSTEIN_WEB = JUNK_EMAILERS + KRASSNER_RECIPIENTS + [
@@ -53,6 +69,19 @@ INVALID_FOR_EPSTEIN_WEB = JUNK_EMAILERS + KRASSNER_RECIPIENTS + [
53
69
  ]
54
70
 
55
71
 
72
+ def print_email_timeline(epstein_files: EpsteinFiles) -> None:
73
+ """Print a table of all emails in chronological order."""
74
+ emails = Document.sort_by_timestamp([e for e in epstein_files.non_duplicate_emails() if not e.is_junk_mail()])
75
+ title = f'Table of All {len(emails):,} Non-Junk Emails in Chronological Order (actual emails below)'
76
+ table = Email.build_emails_table(emails, title=title, show_length=True)
77
+ console.print(Padding(table, (2, 0)))
78
+ print_subtitle_panel('The Chronologically Ordered Emails')
79
+ console.line()
80
+
81
+ for email in emails:
82
+ console.print(email)
83
+
84
+
56
85
  def print_emails_section(epstein_files: EpsteinFiles) -> list[Email]:
57
86
  """Returns emails that were printed (may contain dupes if printed for both author and recipient)."""
58
87
  print_section_header(('Selections from ' if not args.all_emails else '') + 'His Emails')
@@ -70,7 +99,7 @@ def print_emails_section(epstein_files: EpsteinFiles) -> list[Email]:
70
99
 
71
100
  print_other_page_link(epstein_files)
72
101
  console.line(2)
73
- console.print(table_of_selected_emailers(emailers_to_print, epstein_files))
102
+ console.print(_table_of_selected_emailers(emailers_to_print, epstein_files))
74
103
  console.print(Padding(_all_emailers_table(epstein_files), (2, 0)))
75
104
 
76
105
  for author in emailers_to_print:
@@ -83,8 +112,19 @@ def print_emails_section(epstein_files: EpsteinFiles) -> list[Email]:
83
112
  print_color_key()
84
113
  num_emails_printed_since_last_color_key = 0
85
114
 
86
- if not args.names:
87
- epstein_files.print_email_device_info()
115
+ if args.names:
116
+ return already_printed_emails
117
+
118
+ # Print other interesting emails
119
+ already_printed_ids = [email.file_id for email in already_printed_emails]
120
+ extra_emails = [e for e in epstein_files.for_ids(INTERESTING_EMAIL_IDS) if e.file_id not in already_printed_ids]
121
+ print_subtitle_panel(OTHER_INTERESTING_EMAILS_SUBTITLE)
122
+ console.line()
123
+
124
+ for other_email in extra_emails:
125
+ console.print(other_email)
126
+
127
+ epstein_files.print_email_device_info()
88
128
 
89
129
  if args.all_emails:
90
130
  _verify_all_emails_were_printed(epstein_files, already_printed_emails)
@@ -96,8 +136,9 @@ def print_emails_section(epstein_files: EpsteinFiles) -> list[Email]:
96
136
 
97
137
 
98
138
  def print_json_files(epstein_files: EpsteinFiles):
139
+ """Print all the JsonFile objects"""
99
140
  if args.build:
100
- json_data = {json_file.url_slug: json_file.json_data() for json_file in epstein_files.json_files}
141
+ json_data = {jf.url_slug: jf.json_data() for jf in epstein_files.json_files}
101
142
 
102
143
  with open(JSON_FILES_JSON_PATH, 'w') as f:
103
144
  f.write(json.dumps(json_data, sort_keys=True))
@@ -109,6 +150,17 @@ def print_json_files(epstein_files: EpsteinFiles):
109
150
  console.print_json(json_file.json_str(), indent=4, sort_keys=False)
110
151
 
111
152
 
153
+ def print_json_metadata(epstein_files: EpsteinFiles) -> None:
154
+ json_str = epstein_files.json_metadata()
155
+
156
+ if args.build:
157
+ with open(JSON_METADATA_PATH, 'w') as f:
158
+ f.write(json_str)
159
+ log_file_write(JSON_METADATA_PATH)
160
+ else:
161
+ console.print_json(json_str, indent=4, sort_keys=True)
162
+
163
+
112
164
  def print_json_stats(epstein_files: EpsteinFiles) -> None:
113
165
  console.line(5)
114
166
  console.print(Panel('JSON Stats Dump', expand=True, style='reverse bold'), '\n')
@@ -152,91 +204,6 @@ def print_text_messages_section(imessage_logs: list[MessengerLog]) -> None:
152
204
  console.line(2)
153
205
 
154
206
 
155
- def table_of_selected_emailers(_list: list[str | None], epstein_files: EpsteinFiles) -> Table:
156
- """Add the first emailed_at timestamp for each emailer if 'epstein_files' provided."""
157
- header_pfx = '' if args.all_emails else 'Selected '
158
- table = build_table(f'{header_pfx}Email Conversations Grouped by Counterparty Will Appear in this Order')
159
- table.add_column('Start Date')
160
- table.add_column('Name', max_width=25, no_wrap=True)
161
- table.add_column('Category', justify='center', style='dim italic')
162
- table.add_column('Num', justify='right', style='wheat4')
163
- table.add_column('Info', style='white italic')
164
- current_year = 1990
165
- current_year_month = current_year * 12
166
- grey_idx = 0
167
-
168
- for i, name in enumerate(_list):
169
- earliest_email_date = (epstein_files.earliest_email_at(name) or FALLBACK_TIMESTAMP).date()
170
- year_months = (earliest_email_date.year * 12) + earliest_email_date.month
171
-
172
- # Color year rollovers more brightly
173
- if current_year != earliest_email_date.year:
174
- grey_idx = 0
175
- elif current_year_month != year_months:
176
- grey_idx = ((current_year_month - 1) % 12) + 1
177
-
178
- current_year_month = year_months
179
- current_year = earliest_email_date.year
180
- category = get_category_for_name(name)
181
- info = get_info_for_name(name)
182
-
183
- if category and category.plain == 'paula_heil_fisher': # TODO: hacky
184
- category = None
185
- elif category and info:
186
- info = info.removeprefix(f"{category.plain}, ")
187
- elif not name:
188
- info = Text('(emails whose author or recipient could not be determined)', style='medium_purple4')
189
-
190
- table.add_row(
191
- Text(str(earliest_email_date), style=f"grey{GREY_NUMBERS[grey_idx]}"),
192
- Text(name or UNKNOWN, style=get_style_for_name(name or UNKNOWN, default_style='dim')),
193
- category,
194
- f"{len(epstein_files.emails_for(name)):,}",
195
- info or '',
196
- )
197
-
198
- return table
199
-
200
-
201
- def write_complete_emails_timeline(epstein_files: EpsteinFiles) -> None:
202
- """Print a table of all emails in chronological order."""
203
- emails = [email for email in epstein_files.non_duplicate_emails() if not email.is_junk_mail()]
204
- table = build_table(f'All {len(emails):,} Non-Junk Emails in Chronological Order', highlight=True)
205
- table.add_column('ID', style=TIMESTAMP_DIM)
206
- table.add_column('Sent At', style='dim')
207
- table.add_column('Author', max_width=20)
208
- table.add_column('Recipients', max_width=22)
209
- table.add_column('Length', justify='right', style='wheat4')
210
- table.add_column('Subject')
211
-
212
- for email in Document.sort_by_timestamp(emails):
213
- if email.is_junk_mail():
214
- continue
215
-
216
- table.add_row(
217
- email.epstein_media_link(link_txt=email.source_file_id()),
218
- email.timestamp_without_seconds(),
219
- email.author_txt(),
220
- email.recipients_txt(max_full_names=1),
221
- f"{email.length()}",
222
- email.subject(),
223
- )
224
-
225
- console.line(2)
226
- console.print(table)
227
-
228
-
229
- def write_json_metadata(epstein_files: EpsteinFiles) -> None:
230
- json_str = epstein_files.json_metadata()
231
-
232
- if args.build:
233
- with open(JSON_METADATA_PATH, 'w') as f:
234
- f.write(json_str)
235
- log_file_write(JSON_METADATA_PATH)
236
- else:
237
- console.print_json(json_str, indent=4, sort_keys=True)
238
-
239
-
240
207
  def write_urls() -> None:
241
208
  """Write _URL style constant variables to URLS_ENV file so bash scripts can load as env vars."""
242
209
  url_vars = {k: v for k, v in vars(output_files).items() if k.endswith('URL') and not k.startswith('GH')}
@@ -263,7 +230,7 @@ def _all_emailers_table(epstein_files: EpsteinFiles) -> Table:
263
230
  attributed_emails = [e for e in epstein_files.non_duplicate_emails() if e.author]
264
231
  footer = f"(identified {len(epstein_files.email_author_counts)} authors of {len(attributed_emails):,}"
265
232
  footer = f"{footer} out of {len(epstein_files.non_duplicate_emails()):,} emails)"
266
- counts_table = build_table("All of the Email Counterparties Who Appear in the Files", caption=footer)
233
+ counts_table = build_table("Everyone Who Sent or Received an Email in the Files", caption=footer)
267
234
 
268
235
  add_cols_to_table(counts_table, [
269
236
  'Name',
@@ -281,7 +248,7 @@ def _all_emailers_table(epstein_files: EpsteinFiles) -> Table:
281
248
 
282
249
  emailer_counts = {
283
250
  emailer: epstein_files.email_author_counts[emailer] + epstein_files.email_recipient_counts[emailer]
284
- for emailer in epstein_files.all_emailers(True)
251
+ for emailer in epstein_files.all_emailers(include_useless=True)
285
252
  }
286
253
 
287
254
  for name, count in sort_dict(emailer_counts):
@@ -317,6 +284,57 @@ def _is_ok_for_epstein_web(name: str | None) -> bool:
317
284
  return True
318
285
 
319
286
 
287
+ def _table_of_selected_emailers(_list: list[str | None], epstein_files: EpsteinFiles) -> Table:
288
+ """Add the first emailed_at timestamp for each emailer if 'epstein_files' provided."""
289
+ header_pfx = '' if args.all_emails else 'Selected '
290
+ table = build_table(f'{header_pfx}Email Conversations Grouped by Counterparty Will Appear in this Order')
291
+ table.add_column('Start Date')
292
+ table.add_column('Name', max_width=25, no_wrap=True)
293
+ table.add_column('Category', justify='center', style='dim italic')
294
+ table.add_column('Num', justify='right', style='wheat4')
295
+ table.add_column('Info', style='white italic')
296
+ current_year = 1990
297
+ current_year_month = current_year * 12
298
+ grey_idx = 0
299
+
300
+ for i, name in enumerate(_list):
301
+ earliest_email_date = (epstein_files.earliest_email_at(name)).date()
302
+ year_months = (earliest_email_date.year * 12) + earliest_email_date.month
303
+
304
+ # Color year rollovers more brightly
305
+ if current_year != earliest_email_date.year:
306
+ grey_idx = 0
307
+ elif current_year_month != year_months:
308
+ grey_idx = ((current_year_month - 1) % 12) + 1
309
+
310
+ current_year_month = year_months
311
+ current_year = earliest_email_date.year
312
+ category = get_category_txt_for_name(name)
313
+ info = get_info_for_name(name)
314
+ style = get_style_for_name(name, default_style='none')
315
+
316
+ if name == JEFFREY_EPSTEIN:
317
+ info = Text('(emails sent by Epstein to himself that would not otherwise be printed)', style=ALT_INFO_STYLE)
318
+ if category and category.plain == 'paula': # TODO: hacky
319
+ category = None
320
+ elif category and info:
321
+ info = info.removeprefix(f"{category.plain}, ").removeprefix(category.plain)
322
+ elif not name:
323
+ info = Text('(emails whose author or recipient could not be determined)', style=ALT_INFO_STYLE)
324
+ elif style == 'none' and '@' not in name and not (category or info):
325
+ info = QUESTION_MARKS_TXT
326
+
327
+ table.add_row(
328
+ Text(str(earliest_email_date), style=f"grey{GREY_NUMBERS[grey_idx]}"),
329
+ styled_name(name, default_style='dim'),
330
+ category,
331
+ f"{len(epstein_files.emails_for(name)):,}",
332
+ info or '',
333
+ )
334
+
335
+ return table
336
+
337
+
320
338
  def _verify_all_emails_were_printed(epstein_files: EpsteinFiles, already_printed_emails: list[Email]) -> None:
321
339
  """Log warnings if some emails were never printed."""
322
340
  email_ids_that_were_printed = set([email.file_id for email in already_printed_emails])
@@ -1,10 +1,11 @@
1
1
  # Rich reference: https://rich.readthedocs.io/en/latest/reference.html
2
2
  import json
3
+ from copy import deepcopy
3
4
  from os import devnull
4
5
  from pathlib import Path
5
6
 
6
7
  from rich.align import Align
7
- from rich.console import Console, RenderableType
8
+ from rich.console import Console, Group, RenderableType
8
9
  from rich.markup import escape
9
10
  from rich.panel import Panel
10
11
  from rich.padding import Padding
@@ -14,23 +15,23 @@ from rich.theme import Theme
14
15
 
15
16
  from epstein_files.util.constant.html import CONSOLE_HTML_FORMAT, HTML_TERMINAL_THEME, PAGE_TITLE
16
17
  from epstein_files.util.constant.names import UNKNOWN
17
- from epstein_files.util.constant.strings import DEFAULT, EMAIL, NA, QUESTION_MARKS, TEXT_MESSAGE
18
+ from epstein_files.util.constant.strings import DEFAULT, EMAIL, NA, TEXT_MESSAGE
18
19
  from epstein_files.util.constant.urls import *
19
- from epstein_files.util.constants import FALLBACK_TIMESTAMP, HEADER_ABBREVIATIONS
20
- from epstein_files.util.data import json_safe
20
+ from epstein_files.util.constants import HEADER_ABBREVIATIONS
21
+ from epstein_files.util.data import json_safe, without_falsey
21
22
  from epstein_files.util.env import args
22
23
  from epstein_files.util.file_helper import log_file_write
23
- from epstein_files.util.highlighted_group import (ALL_HIGHLIGHTS, HIGHLIGHTED_NAMES, EpsteinHighlighter,
24
- get_category_for_name, get_info_for_name, get_style_for_name)
24
+ from epstein_files.util.highlighted_group import ALL_HIGHLIGHTS, HIGHLIGHTED_NAMES, EpsteinHighlighter
25
25
  from epstein_files.util.logging import logger
26
26
 
27
27
  TITLE_WIDTH = 50
28
+ SUBTITLE_WIDTH = 110
28
29
  MIN_AUTHOR_PANEL_WIDTH = 80
29
30
  NUM_COLOR_KEY_COLS = 4
30
31
  NA_TXT = Text(NA, style='dim')
32
+ SUBTITLE_PADDING = (2, 0, 1, 0)
31
33
  GREY_NUMBERS = [58, 39, 39, 35, 30, 27, 23, 23, 19, 19, 15, 15, 15]
32
34
 
33
- DEFAULT_NAME_STYLE = 'gray46'
34
35
  INFO_STYLE = 'white dim italic'
35
36
  KEY_STYLE = 'honeydew2 bold'
36
37
  LAST_TIMESTAMP_STYLE = 'wheat4'
@@ -89,17 +90,14 @@ def add_cols_to_table(table: Table, col_names: list[str | dict]) -> None:
89
90
 
90
91
  if isinstance(col, dict):
91
92
  col_name = col['name']
92
- kwargs = col
93
+ kwargs = deepcopy(col)
94
+ kwargs['justify'] = kwargs.get('justify', justify)
93
95
  del kwargs['name']
94
-
95
- if 'justify' in col:
96
- justify = col['justify']
97
- del col['justify']
98
96
  else:
99
97
  col_name = col
100
- kwargs = {}
98
+ kwargs = {'justify': justify}
101
99
 
102
- table.add_column(col_name, justify=justify, **kwargs)
100
+ table.add_column(col_name, **kwargs)
103
101
 
104
102
 
105
103
  def build_highlighter(pattern: str) -> EpsteinHighlighter:
@@ -151,17 +149,17 @@ def parenthesize(msg: str | Text, style: str = '') -> Text:
151
149
  return Text('(', style=style).append(txt).append(')')
152
150
 
153
151
 
154
- def print_author_panel(msg: str, color: str | None, footer: str | None = None) -> None:
152
+ def print_author_panel(msg: str, footer: str | None, style: str | None) -> None:
155
153
  """Print a panel with the name of an emailer and a few tidbits of information about them."""
156
- color = 'white' if (not color or color == DEFAULT) else color
157
- width = max(MIN_AUTHOR_PANEL_WIDTH, len(msg) + 4)
158
- panel = Panel(Text(msg, justify='center'), width=width, style=f"black on {color} bold")
159
- console.print('\n', Align.center(panel))
154
+ style = 'white' if (not style or style == DEFAULT) else style
155
+ panel_style = f"black on {style} bold"
156
+ width = max(MIN_AUTHOR_PANEL_WIDTH, len(msg) + 4, len(footer or '') + 8)
157
+ elements: list[RenderableType] = [Panel(Text(msg, justify='center'), width=width, style=panel_style)]
160
158
 
161
159
  if footer:
162
- console.print(Align.center(f"({footer})"), highlight=False, style=f'{color} italic')
160
+ elements.append(Text(f"({footer})", justify='center', style=f"{style} italic"))
163
161
 
164
- console.line()
162
+ print_centered(Padding(Group(*elements), (2, 0, 1, 0)))
165
163
 
166
164
 
167
165
  def print_centered(obj: RenderableType, style: str = '') -> None:
@@ -188,7 +186,8 @@ def print_color_key() -> None:
188
186
  print_centered(vertically_pad(color_table))
189
187
 
190
188
 
191
- def print_title_page_header(epstein_files: 'EpsteinFiles') -> None:
189
+ def print_title_page_header() -> None:
190
+ """Top half of the title page."""
192
191
  print_page_title(width=TITLE_WIDTH)
193
192
  site_type = EMAIL if (args.all_emails or args.email_timeline) else TEXT_MESSAGE
194
193
  title = f"This is the " + ('chronological ' if args.email_timeline else '') + f"Epstein {site_type.title()}s Page"
@@ -209,6 +208,7 @@ def print_title_page_header(epstein_files: 'EpsteinFiles') -> None:
209
208
 
210
209
 
211
210
  def print_title_page_tables(epstein_files: 'EpsteinFiles') -> None:
211
+ """Bottom half of the title page."""
212
212
  _print_external_links()
213
213
  console.line()
214
214
  _print_abbreviations_table()
@@ -246,7 +246,7 @@ def print_other_page_link(epstein_files: 'EpsteinFiles') -> None:
246
246
  print_centered(parenthesize(txt), style=OTHER_PAGE_MSG_STYLE)
247
247
  chrono_emails_markup = link_text_obj(CHRONOLOGICAL_EMAILS_URL, 'a page', style='light_slate_grey bold')
248
248
  chrono_emails_txt = Text(f"there's also ").append(chrono_emails_markup)
249
- chrono_emails_txt.append(' with a table of all the emails in chronological order')
249
+ chrono_emails_txt.append(' with all the emails in chronological order')
250
250
  print_centered(parenthesize(chrono_emails_txt), style=OTHER_PAGE_MSG_STYLE)
251
251
 
252
252
 
@@ -259,16 +259,9 @@ def print_page_title(expand: bool = True, width: int | None = None) -> None:
259
259
  console.line(2)
260
260
 
261
261
 
262
- def print_subtitle_panel(msg: str, style: str = 'black on white', padding: tuple | None = None, centered: bool = False) -> None:
263
- _padding: list[int] = list(padding or [0, 0, 0, 0])
264
- _padding[2] += 1 # Bottom pad
265
- actual_padding: tuple[int, int, int, int] = tuple(_padding)
266
- panel = Panel(Text.from_markup(msg, justify='center'), width=70, style=style)
267
-
268
- if centered:
269
- console.print(Align.center(Padding(panel, actual_padding)))
270
- else:
271
- console.print(Padding(panel, actual_padding))
262
+ def print_subtitle_panel(msg: str, style: str = 'black on white') -> None:
263
+ panel = Panel(Text.from_markup(msg, justify='center'), width=SUBTITLE_WIDTH, style=style)
264
+ print_centered(Padding(panel, SUBTITLE_PADDING))
272
265
 
273
266
 
274
267
  def print_section_header(msg: str, style: str = SECTION_HEADER_STYLE, is_centered: bool = False) -> None:
@@ -306,8 +299,8 @@ def wrap_in_markup_style(msg: str, style: str | None = None) -> str:
306
299
  return msg
307
300
 
308
301
 
309
- def write_html(output_path: Path) -> None:
310
- if not args.build:
302
+ def write_html(output_path: Path | None) -> None:
303
+ if not output_path:
311
304
  logger.warning(f"Not writing HTML because args.build={args.build}.")
312
305
  return
313
306
 
@@ -237,8 +237,7 @@ def write_word_counts_html() -> None:
237
237
  print_color_key()
238
238
  console.line()
239
239
  console.print(word_count)
240
- console.line(2)
241
- print_subtitle_panel(f"{len(COMMON_WORDS_LIST):,} Excluded Words", centered=True)
240
+ print_subtitle_panel(f"{len(COMMON_WORDS_LIST):,} Excluded Words")
242
241
  console.print(', '.join(COMMON_WORDS_LIST), highlight=False)
243
242
  write_html(WORD_COUNT_HTML_PATH)
244
243
  timer.print_at_checkpoint(f"Finished counting words")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epstein-files
3
- Version: 1.1.2
3
+ Version: 1.1.5
4
4
  Summary: Tools for working with the Jeffrey Epstein documents released in November 2025.
5
5
  Home-page: https://michelcrypt4d4mus.github.io/epstein_text_messages/
6
6
  License: GPL-3.0-or-later
@@ -81,6 +81,9 @@ epstein_diff 030999 020442
81
81
  ```
82
82
 
83
83
  The first time you run anything it will take a few minutes to fix all the janky OCR text, attribute the redacted emails, etc. After that things will be quick.
84
+
85
+ The commands used to build the various sites that are deployed on Github Pages can be found in [`deploy.sh`](./deploy.sh).
86
+
84
87
  Run `epstein_generate --help` for command line option assistance.
85
88
 
86
89
  **Optional:** There are a handful of emails that I extracted from the legal filings they were contained in. If you want to include these files in your local analysis you'll need to copy those files from the repo into your local document directory. Something like:
@@ -0,0 +1,33 @@
1
+ epstein_files/__init__.py,sha256=mp1fugQzZ_5RwSbs8JSxx_17hC8W9YL0I9j5J9LS7Jw,5278
2
+ epstein_files/documents/communication.py,sha256=NzcZ3vQBjVAovasnxpUyII4weycMaJ2T3fc_8d4eg-U,1875
3
+ epstein_files/documents/document.py,sha256=z8l65DvgCMrUbVpnhfYUPYtLBqlDN8l-88zZQWWOxAE,17527
4
+ epstein_files/documents/email.py,sha256=pVoW-w9QfvJDI4DeGAxyywXYHf4VP6hKe5Ly16QtOLA,43928
5
+ epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
+ epstein_files/documents/imessage/text_message.py,sha256=pflCbV4qamJa0ueJG60ifbk0xeUJrfFzf-NVIGJLcuU,3353
7
+ epstein_files/documents/json_file.py,sha256=WcZW5NNqA67rHTdopbOGtup00muNaLlvrNgKb-K4zO8,1504
8
+ epstein_files/documents/messenger_log.py,sha256=8EVNnyTKuUeeso9R5vXg_sJf2Ont33e66rMvbzX40Rc,7402
9
+ epstein_files/documents/other_file.py,sha256=TeEzsfGN_mTFZPhfyt9ihxK9oTCYwI8sRLplTsgpOMY,9893
10
+ epstein_files/epstein_files.py,sha256=LdaDMJzUPQuiLNTpsGB3PbojyjVTwMJehjypKyN8V2I,15331
11
+ epstein_files/util/constant/common_words.py,sha256=C1JERPnOGHV2UMC71aEue1i9QTQog-RfT3IzdcYQOYQ,3702
12
+ epstein_files/util/constant/html.py,sha256=MFooFV8KfFBCm9hL1u6A3hi_u37i7lL6UKAYoKQj3PI,1505
13
+ epstein_files/util/constant/names.py,sha256=7rnBq86jaqyDJtpa-nw6zQ029kfLeMhKto66kjkGeSg,10412
14
+ epstein_files/util/constant/output_files.py,sha256=et1y3AzkxKqK0k-wDhMEsQFMfoXrUpoJCn6nQONurkU,1911
15
+ epstein_files/util/constant/strings.py,sha256=05OFmCyxXuH9TwemT9TZNyHmvYkbi5iH9E5nqBC4C0c,1991
16
+ epstein_files/util/constant/urls.py,sha256=VqgqxC2IbX90yw9kfGTwAwc7VVo46TCgDVrkPy3adV4,5127
17
+ epstein_files/util/constants.py,sha256=cF0D3GnpNZUuJiNZjU2qxuNoIzyMq_tDYHcvgYvoTQk,118756
18
+ epstein_files/util/data.py,sha256=XVPXb3qjjv5CdpORvvJjecZqxI7DdhMCQesu-4lqN0Q,3413
19
+ epstein_files/util/doc_cfg.py,sha256=6ErYIgDazH0WbJ27VvMwNrkKytlYAbxHqq1n_surxus,9338
20
+ epstein_files/util/env.py,sha256=5ZIwBUlIg37HBq_Z_DtkhXNDxPtnxOtJ_HD7ek3IoQI,6555
21
+ epstein_files/util/file_helper.py,sha256=MpG1hI7DGs05fV9KSVb_ltc98DC8tv1E_TTo5X_E7Js,3010
22
+ epstein_files/util/highlighted_group.py,sha256=YryxT0uJyOlcrGjgERaCOvlZwPRXieaniv8h_yhCcoE,54339
23
+ epstein_files/util/logging.py,sha256=F45YqEKAiIb0rDZnOB7XuaY-dOkOKrsfSzO1VVqY508,2097
24
+ epstein_files/util/output.py,sha256=5hPiYVR27azXfKQoqEAmXy9CvinUklKvsP6m3DCnsCE,14800
25
+ epstein_files/util/rich.py,sha256=J7IaXXF2duuajzwvCPMIhDZZfL1y63c8rQ00lumYwAs,14347
26
+ epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
27
+ epstein_files/util/timer.py,sha256=QqqXAQofKPWkDngNwG0mOqRn7nHcAR-BGQjqAwZfXoE,840
28
+ epstein_files/util/word_count.py,sha256=rTAo-C_I8O_y2tfUfVCYAMqXgSe1oET0TxGKepYdtiE,9199
29
+ epstein_files-1.1.5.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
+ epstein_files-1.1.5.dist-info/METADATA,sha256=pLpbillvKcnF10ch839Eq0sxsi8u30T7_9k49WEHW18,5991
31
+ epstein_files-1.1.5.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
+ epstein_files-1.1.5.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
+ epstein_files-1.1.5.dist-info/RECORD,,
@@ -1,33 +0,0 @@
1
- epstein_files/__init__.py,sha256=dPSYqe6CZyXFJviCsrVLPy-uxJxG5xS_W9ZDjUih5f0,5484
2
- epstein_files/documents/communication.py,sha256=4xcmCg4108D4Rln4tiXbm5pRBRfBGpMxcCORUCMnT6k,1908
3
- epstein_files/documents/document.py,sha256=eQ0IgOUZiKz-KFgUwkWariQ5HqyM2VY3ZCJC4qRsnDg,17401
4
- epstein_files/documents/email.py,sha256=b5klJTrqTydaSupC5fJkV64nDxulkWE1DAvXF8FaLCY,43369
5
- epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
- epstein_files/documents/imessage/text_message.py,sha256=w_U2bNIKtH7rMSNP4Q0BoTDrQZ6HE2IUSFjy6rBxrgY,3348
7
- epstein_files/documents/json_file.py,sha256=WcZW5NNqA67rHTdopbOGtup00muNaLlvrNgKb-K4zO8,1504
8
- epstein_files/documents/messenger_log.py,sha256=pAHH8FntEyQCwoVFI3B5utSqS5LKhQrj5UD1hl3pnbg,7419
9
- epstein_files/documents/other_file.py,sha256=TeEzsfGN_mTFZPhfyt9ihxK9oTCYwI8sRLplTsgpOMY,9893
10
- epstein_files/epstein_files.py,sha256=K6hgDlwHFNbhdIQcc5RJN_-g_xLhNLQ1yelpzCZrZBw,15210
11
- epstein_files/util/constant/common_words.py,sha256=C1JERPnOGHV2UMC71aEue1i9QTQog-RfT3IzdcYQOYQ,3702
12
- epstein_files/util/constant/html.py,sha256=MFooFV8KfFBCm9hL1u6A3hi_u37i7lL6UKAYoKQj3PI,1505
13
- epstein_files/util/constant/names.py,sha256=yHZ46IcrzOOEr6mdTllxaG_YvLrdhmJlWCwIGv4FaiU,10738
14
- epstein_files/util/constant/output_files.py,sha256=et1y3AzkxKqK0k-wDhMEsQFMfoXrUpoJCn6nQONurkU,1911
15
- epstein_files/util/constant/strings.py,sha256=2TLP_TWgErsXb9lF8k0lZVAAQ8QAc5ytKQi3PD9CAzY,1961
16
- epstein_files/util/constant/urls.py,sha256=VqgqxC2IbX90yw9kfGTwAwc7VVo46TCgDVrkPy3adV4,5127
17
- epstein_files/util/constants.py,sha256=ZllrMB7Imlp4ihviGOMxB5qU_hnbS7rP3PnjS0fVbAI,112742
18
- epstein_files/util/data.py,sha256=JccGFZGiCGm7XtwpQTocIjGYOr6hTUpEPwHhjyW9Xnc,3164
19
- epstein_files/util/doc_cfg.py,sha256=aBIm0hyxf-aeMsb8ZUNiQFVsPFimjVUIkrVdDrg1iQU,9105
20
- epstein_files/util/env.py,sha256=MbS-wD0iMJyg6u-adxVGvTlXY4-ubzIjG20ovz1EMHU,6147
21
- epstein_files/util/file_helper.py,sha256=PGPqXmt4Oz4bE45ybvaCZfI0w_PGKirTsrv7xw86gmY,2903
22
- epstein_files/util/highlighted_group.py,sha256=Pt34bfLjkdl7VBEogeJoofXhJC9fTPHYCgb4NNDlPpI,52422
23
- epstein_files/util/logging.py,sha256=F45YqEKAiIb0rDZnOB7XuaY-dOkOKrsfSzO1VVqY508,2097
24
- epstein_files/util/output.py,sha256=IXBiCQYy6Z2BUGDCLeQUfJ1NUzTItjvgg-k0i4KpOzA,13751
25
- epstein_files/util/rich.py,sha256=0hyzML8yCSF6FfjQIt7aJyEqG8unQhDOQzfd7e6FTAI,14599
26
- epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
27
- epstein_files/util/timer.py,sha256=QqqXAQofKPWkDngNwG0mOqRn7nHcAR-BGQjqAwZfXoE,840
28
- epstein_files/util/word_count.py,sha256=J6aZkodXwowf09GykLgJuqwSRzrMjvefgKiM8S-T9LA,9234
29
- epstein_files-1.1.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
- epstein_files-1.1.2.dist-info/METADATA,sha256=clg2flS9u3aeaYxXqlwvnemMyDKBHuuMvUgiJj8d4qs,5866
31
- epstein_files-1.1.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
- epstein_files-1.1.2.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
- epstein_files-1.1.2.dist-info/RECORD,,