epstein-files 1.0.12__py3-none-any.whl → 1.0.14__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.
@@ -299,23 +299,10 @@ HIGHLIGHTED_NAMES = [
299
299
  KEN_STARR: 'head of the Monica Lewinsky investigation against Bill Clinton',
300
300
  }
301
301
  ),
302
- HighlightedNames(
303
- label='friend',
304
- style='tan',
305
- pattern=r"Andrew Farkas|Thomas\s*(J\.?\s*)?Barrack(\s*Jr)?",
306
- emailers = {
307
- DAVID_STERN: f'emailed Epstein from Moscow, appears to know chairman of {DEUTSCHE_BANK}',
308
- JONATHAN_FARKAS: "heir to the Alexander's department store fortune",
309
- 'linkspirit': "Skype username of someone Epstein communicated with",
310
- 'Peter Thomas Roth': 'student of Epstein at Dalton, skincare company founder',
311
- STEPHEN_HANSON: None,
312
- TOM_BARRACK: 'long time friend of Trump',
313
- }
314
- ),
315
302
  HighlightedNames(
316
303
  label=FINANCE,
317
304
  style='green',
318
- pattern=r'Apollo|Ari\s*Glass|Bank|(Bernie\s*)?Madoff|Black(rock|stone)|B\s*of\s*A|Boothbay(\sFund\sManagement)?|Chase\s*Bank|Credit\s*Suisse|DB|Deutsche\s*(Asset|Bank)|Electron\s*Capital\s*(Partners)?|Fenner|FRBNY|Goldman(\s*Sachs)|HSBC|Invesco|(Janet\s*)?Yellen|(Jerome\s*)?Powell(?!M\. Cabot)|(Jimmy\s*)?Cayne|JPMC?|j\.?p\.?\s*morgan(\.?com|\s*Chase)?|Madoff|Merrill(\s*Lynch)?|(Michael\s*)?(Cembalest|Milken)|Mizrahi\s*Bank|MLPF&S|((anti.?)?money\s+)?launder(s?|ers?|ing)?(\s+money)?|Morgan Stanley|(Peter L. )?Scher|(Ray\s*)?Dalio|Schwartz?man|Serageldin|UBS|us.gio@jpmorgan.com',
305
+ pattern=r'Apollo|Ari\s*Glass|Bank|(Bernie\s*)?Madoff|Black(rock|stone)|B\s*of\s*A|Boothbay(\sFund\sManagement)?|Chase\s*Bank|Credit\s*Suisse|DB|Deutsche\s*(Asset|Bank)|Electron\s*Capital\s*(Partners)?|Fenner|FRBNY|Goldman(\s*Sachs)|HSBC|Invesco|(Janet\s*)?Yellen|(Jerome\s*)?Powell(?!M\. Cabot)|(Jimmy\s*)?Cayne|JPMC?|j\.?p\.?\s*morgan(\.?com|\s*Chase)?|Madoff|Merrill(\s*Lynch)?|(Michael\s*)?(Cembalest|Milken)|Mizrahi\s*Bank|MLPF&S|((anti.?)?money\s+)?launder(s?|ers?|ing)?(\s+money)?|Morgan Stanley|(Peter L. )?Scher|(Ray\s*)?Dalio|(Richard\s*)?LeFrak|Schwartz?man|Serageldin|UBS|us.gio@jpmorgan.com',
319
306
  emailers={
320
307
  AMANDA_ENS: 'Citigroup',
321
308
  BRAD_WECHSLER: f"head of {LEON_BLACK}'s personal investment vehicle according to FT",
@@ -332,9 +319,23 @@ HIGHLIGHTED_NAMES = [
332
319
  PAUL_MORRIS: 'Deutsche Bank',
333
320
  }
334
321
  ),
322
+ HighlightedNames(
323
+ label='friend',
324
+ style='tan',
325
+ pattern=r"Andrew Farkas|Thomas\s*(J\.?\s*)?Barrack(\s*Jr)?",
326
+ emailers = {
327
+ DANGENE_AND_JENNIE_ENTERPRISE: 'founders of the members-only CORE club',
328
+ DAVID_STERN: f'emailed Epstein from Moscow, appears to know chairman of {DEUTSCHE_BANK}',
329
+ JONATHAN_FARKAS: "heir to the Alexander's department store fortune",
330
+ 'linkspirit': "Skype username of someone Epstein communicated with",
331
+ 'Peter Thomas Roth': 'student of Epstein at Dalton, skincare company founder',
332
+ STEPHEN_HANSON: None,
333
+ TOM_BARRACK: 'long time friend of Trump',
334
+ },
335
+ ),
335
336
  HighlightedNames(
336
337
  label=HARVARD.lower(),
337
- style='deep_pink2',
338
+ style='light_goldenrod3',
338
339
  pattern=r'Cambridge|(Derek\s*)?Bok|Elisa(\s*New)?|Harvard(\s*(Business|Law|University)(\s*School)?)?|(Jonathan\s*)?Zittrain|(Stephen\s*)?Kosslyn',
339
340
  emailers = {
340
341
  "Donald Rubin": f"Professor of Statistics",
@@ -372,14 +373,6 @@ HIGHLIGHTED_NAMES = [
372
373
  style='color(168)',
373
374
  pattern=r'BOJ|(Bank\s+of\s+)?Japan(ese)?|jpy?(?! Morgan)|SG|Singapore|Toky[op]',
374
375
  ),
375
- HighlightedNames(
376
- label='javanka',
377
- style='medium_violet_red',
378
- emailers = {
379
- IVANKA: None,
380
- JARED_KUSHNER: None,
381
- }
382
- ),
383
376
  HighlightedNames(
384
377
  label=JOURNALIST,
385
378
  style='bright_yellow',
@@ -403,7 +396,7 @@ HIGHLIGHTED_NAMES = [
403
396
  HighlightedNames(
404
397
  label='law enforcement',
405
398
  style='color(24) bold',
406
- pattern=r'ag|(Alicia\s*)?Valle|AML|attorney|((Bob|Robert)\s*)?Mueller|(Byung\s)?Pak|CFTC?|CIA|CIS|CVRA|Dep(artmen)?t\.?\s*of\s*(the\s*)?(Justice|Treasury)|DHS|DOJ|FBI|FCPA|FDIC|Federal\s*Bureau\s*of\s*Investigation|FinCEN|FINRA|FOIA|FTC|IRS|(James\s*)?Comey|(Jennifer\s*Shasky\s*)?Calvery|((Judge|Mark)\s*)?(Carney|Filip)|(Kirk )?Blouin|KYC|NIH|NS(A|C)|OCC|OFAC|(Lann?a\s*)?Belohlavek|lawyer|(Michael\s*)?Reiter|OGE|Office\s*of\s*Government\s*Ethics|Police Code Enforcement|(Preet\s*)?Bharara|SCOTUS|SD(FL|NY)|Southern\s*District\s*of\s*(Florida|New\s*York)|SEC|Secret\s*Service|Securities\s*and\s*Exchange\s*Commission|State\s*Dep(artmen)?t|Strzok|Supreme\s*Court|Treasury\s*(Dep(artmen)?t|Secretary)|TSA|USAID|(William\s*J\.?\s*)?Zloch',
399
+ pattern=r'ag|(Alicia\s*)?Valle|AML|(Andrew\s*)?McCabe|attorney|((Bob|Robert)\s*)?Mueller|(Byung\s)?Pak|CFTC?|CIA|CIS|CVRA|Dep(artmen)?t\.?\s*of\s*(the\s*)?(Justice|Treasury)|DHS|DOJ|FBI|FCPA|FDIC|Federal\s*Bureau\s*of\s*Investigation|FinCEN|FINRA|FOIA|FTC|IRS|(James\s*)?Comey|(Jennifer\s*Shasky\s*)?Calvery|((Judge|Mark)\s*)?(Carney|Filip)|(Kirk )?Blouin|KYC|NIH|NS(A|C)|OCC|OFAC|(Lann?a\s*)?Belohlavek|lawyer|(Michael\s*)?Reiter|OGE|Office\s*of\s*Government\s*Ethics|Police Code Enforcement|(Preet\s*)?Bharara|SCOTUS|SD(FL|NY)|SEC|Secret\s*Service|Securities\s*and\s*Exchange\s*Commission|Southern\s*District\s*of\s*(Florida|New\s*York)|State\s*Dep(artmen)?t|Strzok|Supreme\s*Court|Treasury\s*(Dep(artmen)?t|Secretary)|TSA|USAID|(William\s*J\.?\s*)?Zloch',
407
400
  emailers = {
408
401
  ANN_MARIE_VILLAFANA: 'southern district of Florida U.S. Attorney',
409
402
  DANNY_FROST: 'Director of Communications at Manhattan DA',
@@ -462,6 +455,7 @@ HIGHLIGHTED_NAMES = [
462
455
  CHRISTINA_GALBRAITH: f"{REPUTATION_MGMT}, worked on Epstein's Google search results with {TYLER_SHEARS}",
463
456
  IAN_OSBORNE: f"{OSBORNE_LLP} reputation repairer possibly hired by Epstein ca. 2011-06",
464
457
  MICHAEL_SITRICK: 'crisis PR',
458
+ 'Owen Blicksilver': 'OBPR, Inc.',
465
459
  PEGGY_SIEGAL: 'socialite',
466
460
  'R. Couri Hay': None,
467
461
  ROSS_GOW: 'Acuity Reputation Management',
@@ -471,10 +465,10 @@ HIGHLIGHTED_NAMES = [
471
465
  HighlightedNames(
472
466
  label='republicans',
473
467
  style='bold dark_red',
474
- pattern=r'Alberto\sGonzale[sz]|(Alex\s*)?Acosta|(Bill\s*)?Barr|Bill\s*Shine|(Bob\s*)?Corker|(John\s*(R.?\s*)?)Bolton|Broidy|(Chris\s)?Christie|Devin\s*Nunes|(Don\s*)?McGa[hn]n|McMaster|(George\s*)?Nader|GOP|(Brett\s*)?Kavanaugh|Kissinger|Kobach|Koch\s*Brothers|Kolfage|Kudlow|Lewandowski|(Marco\s)?Rubio|(Mark\s*)Meadows|Mattis|McCain|(?<!Merwin Dela )Cruz|(Michael\s)?Hayden|((General|Mike)\s*)?(Flynn|Pence)|(Mitt\s*)?Romney|Mnuchin|Nikki|Haley|(Paul\s+)?(Manafort|Volcker)|(Peter\s)?Navarro|Pompeo|Reagan|Reince|Priebus|Republican|(Rex\s*)?Tillerson|(?<!Cynthia )(Richard\s*)?Nixon|Sasse',
468
+ pattern=r'Alberto\sGonzale[sz]|(Alex\s*)?Acosta|(Bill\s*)?Barr|Bill\s*Shine|(Bob\s*)?Corker|(John\s*(R.?\s*)?)Bolton|Broidy|(Chris\s)?Christie|Devin\s*Nunes|(Don\s*)?McGa[hn]n|McMaster|(George\s*)?Nader|GOP|(Brett\s*)?Kavanaugh|Kissinger|Kobach|Koch\s*Brothers|Kolfage|Kudlow|Lewandowski|(Marco\s)?Rubio|(Mark\s*)Meadows|Mattis|McCain|(?<!Merwin Dela )Cruz|(Michael\s)?Hayden|((General|Mike)\s*)?(Flynn|Pence)|(Mitt\s*)?Romney|Mnuchin|Nikki|Haley|(Paul\s+)?(Manafort|Volcker)|(Peter\s)?Navarro|Pompeo|Reagan|Reince|Priebus|Republican|(Rex\s*)?Tillerson|(?<!Cynthia )(Richard\s*)?Nixon|Sasse|Tea\s*Party',
475
469
  # There's no emails from these people, they're just here to automate the regex creation for both first + last names
476
470
  emailers = {
477
- RUDY_GIULIANI: 'disbarred formed mayor of New York City',
471
+ RUDY_GIULIANI: None,
478
472
  TULSI_GABBARD: None,
479
473
  },
480
474
  ),
@@ -482,7 +476,7 @@ HIGHLIGHTED_NAMES = [
482
476
  label='Rothschild family',
483
477
  style='indian_red',
484
478
  emailers={
485
- ARIANE_DE_ROTHSCHILD: None,
479
+ ARIANE_DE_ROTHSCHILD: 'heiress',
486
480
  JOHNNY_EL_HACHEM: f'Works with {ARIANE_DE_ROTHSCHILD}',
487
481
  },
488
482
  ),
@@ -502,7 +496,7 @@ HIGHLIGHTED_NAMES = [
502
496
  style='light_goldenrod2',
503
497
  pattern=r'Alain Forget|Brotherton|Carl\s*Sagan|Columbia|David Grosof|J(ames|im)\s*Watson|(Lord\s*)?Martin\s*Rees|Massachusetts\s*Institute\s*of\s*Technology|MIT(\s*Media\s*Lab)?|Media\s*Lab|Minsky|((Noam|Valeria)\s*)?Chomsky|Norman\s*Finkelstein|Praluent|Regeneron|(Richard\s*)?Dawkins|Sanofi|Stanford|(Stephen\s*)?Hawking|(Steven?\s*)?Pinker|UCLA',
504
498
  emailers = {
505
- DAVID_HAIG: None,
499
+ DAVID_HAIG: 'evolutionary geneticist?',
506
500
  JOSCHA_BACH: 'cognitive science / AI research',
507
501
  'Daniel Kahneman': 'Nobel economic sciences laureate and cognitivie psychologist (?)',
508
502
  'Ed Boyden': 'Associate Professor, MIT Media Lab neurobiology',
@@ -536,7 +530,7 @@ HIGHLIGHTED_NAMES = [
536
530
  HighlightedNames(
537
531
  label='trump',
538
532
  style='red3 bold',
539
- pattern=r"@?realDonaldTrump|(Alan\s*)?Weiss?elberg|\bDJ?T\b|Donald J. Tramp|(Donald\s+(J\.\s+)?)?Trump(ism|\s*Properties)?|Don(ald| *Jr)(?! Rubin)|Ivana|(Madeleine\s*)?Westerhout|Mar[-\s]*a[-\s]*Lago|(Marla\s*)?Maples|(Matt(hew)? )?Calamari|\bMatt C\b|Melania|(Michael (J.? )?)?Boccio|Rebekah\s*Mercer|Roger\s+Stone|rona|(The\s*)?Art\s*of\s*the\s*Deal",
533
+ pattern=r"@?realDonaldTrump|(Alan\s*)?Weiss?elberg|\bDJ?T\b|Donald J. Tramp|(Donald\s+(J\.\s+)?)?Trump(ism|\s*Properties)?|Don(ald| *Jr)(?! Rubin)|Ivank?a|Jared|Kushner|(Madeleine\s*)?Westerhout|Mar[-\s]*a[-\s]*Lago|(Marla\s*)?Maples|(Matt(hew)? )?Calamari|\bMatt C\b|Melania|(Michael (J.? )?)?Boccio|Rebekah\s*Mercer|Roger\s+Stone|rona|(The\s*)?Art\s*of\s*the\s*Deal",
540
534
  emailers = {
541
535
  'Bruce Moskowitz': "'Trump's health guy' according to Epstein",
542
536
  },
@@ -558,7 +552,7 @@ HIGHLIGHTED_NAMES = [
558
552
  HighlightedNames(
559
553
  label=VIRGIN_ISLANDS,
560
554
  style='sea_green1',
561
- pattern=r'Antigua|Bahamas|Caribb?ean|Dominican\s*Republic|(Great|Little)\s*St.?\s*James|Haiti(an)?|(John\s*)deJongh(\s*Jr\.?)|(Kenneth E\. )?Mapp|Palm\s*Beach(?!\s*Post)|PBI|S(ain)?t.?\s*Thomas|USVI|VI|(The\s*)?Virgin\s*Islands(\s*Daily\s*News)?', # TODO: VI Daily News should be yellow but it's hard bc Daily News xists
555
+ pattern=r'Antigua|Bahamas|Caribb?ean|Dominican\s*Republic|(Great|Little)\s*St.?\s*James|Haiti(an)?|(John\s*)deJongh(\s*Jr\.?)|(Kenneth E\. )?Mapp|Palm\s*Beach(?!\s*Post)|PBI|S(ain)?t.?\s*Thomas|USVI|(?<!Epstein )VI|(The\s*)?Virgin\s*Islands(\s*Daily\s*News)?', # TODO: VI Daily News should be yellow but it's hard bc Daily News xists
562
556
  emailers = {
563
557
  CECILE_DE_JONGH: f'First lady 2007-2015',
564
558
  STACEY_PLASKETT: 'non-voting member of Congress',
@@ -667,7 +661,7 @@ def get_info_for_name(name: str) -> str | None:
667
661
  def get_style_for_category(category: str) -> str | None:
668
662
  if category in CATEGORY_STYLES:
669
663
  return CATEGORY_STYLES[category]
670
- elif category in [CONFERENCE, SPEECH]:
664
+ elif category == CONFERENCE:
671
665
  return f"{get_style_for_category(ACADEMIA)} dim"
672
666
  elif category == SOCIAL:
673
667
  return get_style_for_category(PUBLICIST)
@@ -32,8 +32,6 @@ DEFAULT_EMAILERS = [
32
32
  MASHA_DROKOVA,
33
33
  RENATA_BOLOTOVA,
34
34
  STEVE_BANNON,
35
- OLIVIER_COLOM,
36
- BORIS_NIKOLIC,
37
35
  PRINCE_ANDREW,
38
36
  JIDE_ZEITLIN,
39
37
  DAVID_STERN,
@@ -60,7 +58,7 @@ if len(set(DEFAULT_EMAILERS).intersection(set(DEFAULT_EMAILER_TABLES))) > 0:
60
58
  def print_emails(epstein_files: EpsteinFiles) -> int:
61
59
  """Returns number of emails printed."""
62
60
  print_section_header(('Selections from ' if not args.all_emails else '') + 'His Emails')
63
- print_other_site_link(is_header=False)
61
+ print_all_files_page_link(epstein_files)
64
62
  emailers_to_print: list[str | None]
65
63
  emailer_tables: list[str | None] = []
66
64
  already_printed_emails: list[Email] = []
@@ -69,7 +67,7 @@ def print_emails(epstein_files: EpsteinFiles) -> int:
69
67
  if specified_names:
70
68
  emailers_to_print = specified_names
71
69
  else:
72
- epstein_files.print_emailer_counts_table()
70
+ print_centered(Padding(epstein_files.table_of_emailers(), (2, 0)))
73
71
 
74
72
  if args.all_emails:
75
73
  emailers_to_print = sorted(epstein_files.all_emailers(), key=lambda e: epstein_files.earliest_email_at(e))
@@ -105,8 +103,8 @@ def print_emails(epstein_files: EpsteinFiles) -> int:
105
103
  if args.all_emails:
106
104
  _verify_all_emails_were_printed(epstein_files, already_printed_emails)
107
105
 
108
- fwded_articles = [e for e in already_printed_emails if e.config and e.config.is_fwded_article]
109
- log_msg = f"Rewrote {len(Email.rewritten_header_ids)} email headers (out of {len(already_printed_emails)})"
106
+ fwded_articles = [e for e in already_printed_emails if e.config and e.is_fwded_article()]
107
+ log_msg = f"Rewrote {len(Email.rewritten_header_ids)} of {len(already_printed_emails)} email headers"
110
108
  logger.warning(f"{log_msg}, {len(fwded_articles)} of the emails were forwarded articles.")
111
109
  return len(already_printed_emails)
112
110
 
@@ -125,17 +123,6 @@ def print_json_files(epstein_files: EpsteinFiles):
125
123
  console.print_json(json_file.json_str(), indent=4, sort_keys=False)
126
124
 
127
125
 
128
- def write_json_metadata(epstein_files: EpsteinFiles) -> None:
129
- json_str = epstein_files.json_metadata()
130
-
131
- if args.build:
132
- with open(JSON_METADATA_PATH, 'w') as f:
133
- f.write(json_str)
134
- log_file_write(JSON_METADATA_PATH)
135
- else:
136
- console.print_json(json_str, indent=4, sort_keys=True)
137
-
138
-
139
126
  def print_json_stats(epstein_files: EpsteinFiles) -> None:
140
127
  console.line(5)
141
128
  console.print(Panel('JSON Stats Dump', expand=True, style='reverse bold'), '\n')
@@ -149,21 +136,19 @@ def print_json_stats(epstein_files: EpsteinFiles) -> None:
149
136
  print_json("count_by_month", count_by_month(epstein_files.all_documents()))
150
137
 
151
138
 
152
- def print_text_messages(epstein_files: EpsteinFiles) -> None:
153
- print_section_header('Text Messages')
154
- print_centered("(conversations are sorted chronologically based on timestamp of first message)\n", style='gray30')
155
- authors: list[str | None] = specified_names if specified_names else [JEFFREY_EPSTEIN]
156
- log_files = epstein_files.imessage_logs_for(authors)
157
-
158
- for log_file in log_files:
159
- console.print(Padding(log_file))
160
- console.line(2)
139
+ def write_json_metadata(epstein_files: EpsteinFiles) -> None:
140
+ json_str = epstein_files.json_metadata()
161
141
 
162
- epstein_files.print_imessage_summary()
142
+ if args.build:
143
+ with open(JSON_METADATA_PATH, 'w') as f:
144
+ f.write(json_str)
145
+ log_file_write(JSON_METADATA_PATH)
146
+ else:
147
+ console.print_json(json_str, indent=4, sort_keys=True)
163
148
 
164
149
 
165
150
  def write_urls() -> None:
166
- """Write _URL style constant variables to a file bash scripts can load as env vars."""
151
+ """Write _URL style constant variables to URLS_ENV file so bash scripts can load as env vars."""
167
152
  url_vars = {k: v for k, v in vars(output_files).items() if k.endswith('URL') and not k.startswith('GH')}
168
153
 
169
154
  if not args.suppress_output:
@@ -190,8 +175,8 @@ def _verify_all_emails_were_printed(epstein_files: EpsteinFiles, already_printed
190
175
  logger.warning(f"Printed {len(already_printed_emails):,} emails of {len(email_ids_that_were_printed):,} unique file IDs.")
191
176
  missed_an_email = False
192
177
 
193
- for email in epstein_files.emails:
194
- if email.file_id not in email_ids_that_were_printed and not email.is_duplicate():
178
+ for email in epstein_files.non_duplicate_emails():
179
+ if email.file_id not in email_ids_that_were_printed:
195
180
  logger.warning(f"Failed to print {email.summary()}")
196
181
  missed_an_email = True
197
182
 
@@ -33,6 +33,7 @@ GREY_NUMBERS = [58, 39, 39, 35, 30, 27, 23, 23, 19, 19, 15, 15, 15]
33
33
  DEFAULT_NAME_STYLE = 'gray46'
34
34
  INFO_STYLE = 'white dim italic'
35
35
  KEY_STYLE='honeydew2 bold'
36
+ LAST_TIMESTAMP_STYLE='wheat4'
36
37
  SECTION_HEADER_STYLE = 'bold white on blue3'
37
38
  SOCIAL_MEDIA_LINK_STYLE = 'pale_turquoise4'
38
39
  SUBSTACK_POST_LINK_STYLE = 'bright_cyan'
@@ -79,10 +80,18 @@ console = Console(**CONSOLE_ARGS)
79
80
  highlighter = CONSOLE_ARGS['highlighter']
80
81
 
81
82
 
82
- def add_cols_to_table(table: Table, col_names: list[str]) -> None:
83
+ def add_cols_to_table(table: Table, col_names: list[str | dict]) -> None:
83
84
  """Left most col will be left justified, rest are center justified."""
84
85
  for i, col in enumerate(col_names):
85
- table.add_column(col, justify='left' if i == 0 else 'center')
86
+ if isinstance(col, dict):
87
+ col_name = col['name']
88
+ kwargs = col
89
+ del kwargs['name']
90
+ else:
91
+ col_name = col
92
+ kwargs = {}
93
+
94
+ table.add_column(col_name, justify='left' if i == 0 else 'center', **kwargs)
86
95
 
87
96
 
88
97
  def build_highlighter(pattern: str) -> EpsteinHighlighter:
@@ -93,8 +102,13 @@ def build_highlighter(pattern: str) -> EpsteinHighlighter:
93
102
  return TempHighlighter()
94
103
 
95
104
 
96
- def build_table(title: str | None, **kwargs) -> Table:
97
- return Table(title=title, **{**DEFAULT_TABLE_KWARGS, **kwargs})
105
+ def build_table(title: str | None, cols: list[str | dict] | None = None, **kwargs) -> Table:
106
+ table = Table(title=title, **{**DEFAULT_TABLE_KWARGS, **kwargs})
107
+
108
+ if cols:
109
+ add_cols_to_table(table, cols)
110
+
111
+ return table
98
112
 
99
113
 
100
114
  def join_texts(txts: list[Text], join: str = ' ', encloser: str = '', encloser_style: str = 'wheat4') -> Text:
@@ -129,6 +143,13 @@ def parenthesize(msg: str | Text, style: str = '') -> Text:
129
143
  return Text('(', style=style).append(txt).append(')')
130
144
 
131
145
 
146
+ def print_all_files_page_link(epstein_files: 'EpsteinFiles') -> None:
147
+ markup_msg = link_markup(SITE_URLS[EMAIL], 'the other page', style='light_slate_grey bold')
148
+ txt = Text.from_markup(markup_msg).append(f' is uncurated and has all {len(epstein_files.other_files)}')
149
+ txt.append(f" unclassifiable files and {len(epstein_files.emails):,} emails")
150
+ print_centered(parenthesize(txt), style='dim')
151
+
152
+
132
153
  def print_author_header(msg: str, color: str | None, footer: str | None = None) -> None:
133
154
  txt = Text(msg, justify='center')
134
155
  color = color or 'white'
@@ -174,7 +195,20 @@ def print_header(epstein_files: 'EpsteinFiles') -> None:
174
195
 
175
196
  console.print(f"{not_optimized_msg}.\n", style='dim')
176
197
  print_page_title(width=TITLE_WIDTH)
177
- print_other_site_link()
198
+ site_type: SiteType = EMAIL if args.all_emails else TEXT_MESSAGE
199
+ print_starred_header(f"This is the Epstein {site_type.title()}s site", num_spaces=4, num_stars=14)
200
+ other_site_type: SiteType = TEXT_MESSAGE if site_type == EMAIL else EMAIL
201
+ other_site_msg = "another site with" + (' all of' if other_site_type == EMAIL else '')
202
+ other_site_msg += f" Epstein's {other_site_type}s also generated by this code"
203
+
204
+ markup_msg = link_markup(SITE_URLS[other_site_type], other_site_msg, OTHER_SITE_LINK_STYLE)
205
+ print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
206
+ word_count_link = link_text_obj(WORD_COUNT_URL, 'most frequently used words in the emails and texts', AUX_SITE_LINK_STYLE)
207
+ print_centered(parenthesize(word_count_link))
208
+ metadata_link = link_text_obj(JSON_METADATA_URL, 'author attribution explanations', AUX_SITE_LINK_STYLE)
209
+ print_centered(parenthesize(metadata_link))
210
+ json_link = link_text_obj(WORD_COUNT_URL, "epstein's json files", AUX_SITE_LINK_STYLE)
211
+ print_centered(parenthesize(json_link))
178
212
  _print_external_links()
179
213
  console.line()
180
214
  _print_abbreviations_table()
@@ -238,31 +272,6 @@ def print_numbered_list_of_emailers(_list: list[str | None], epstein_files = Non
238
272
  console.line()
239
273
 
240
274
 
241
- def print_other_site_link(is_header: bool = True) -> None:
242
- """Print a link to the emails site if we're building text messages site and vice versa."""
243
- site_type: SiteType = EMAIL if args.all_emails else TEXT_MESSAGE
244
- link_style = OTHER_SITE_LINK_STYLE if is_header else 'light_slate_grey bold'
245
-
246
- if is_header:
247
- print_starred_header(f"This is the Epstein {site_type.title()}s site", num_spaces=4, num_stars=14)
248
-
249
- other_site_type: SiteType = TEXT_MESSAGE if site_type == EMAIL else EMAIL
250
- other_site_msg = "another site with" + (' all of' if other_site_type == EMAIL else '')
251
- other_site_msg += f" Epstein's {other_site_type}s also generated by this code"
252
- markup_msg = link_markup(SITE_URLS[other_site_type], other_site_msg, link_style)
253
- print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
254
-
255
- if not is_header:
256
- return
257
-
258
- word_count_link = link_text_obj(WORD_COUNT_URL, 'most frequently used words in the emails and texts', AUX_SITE_LINK_STYLE)
259
- print_centered(parenthesize(word_count_link))
260
- metadata_link = link_text_obj(JSON_METADATA_URL, 'author attribution explanations', AUX_SITE_LINK_STYLE)
261
- print_centered(parenthesize(metadata_link))
262
- json_link = link_text_obj(WORD_COUNT_URL, "epstein's json files", AUX_SITE_LINK_STYLE)
263
- print_centered(parenthesize(json_link))
264
-
265
-
266
275
  def print_page_title(expand: bool = True, width: int | None = None) -> None:
267
276
  title_panel = Panel(Text(PAGE_TITLE, justify='center'), expand=expand, style=TITLE_STYLE, width=width)
268
277
  console.print(Align.center(vertically_pad(title_panel)))
@@ -285,7 +294,7 @@ def print_panel(msg: str, style: str = 'black on white', padding: tuple | None =
285
294
  def print_section_header(msg: str, style: str = SECTION_HEADER_STYLE, is_centered: bool = False) -> None:
286
295
  panel = Panel(Text(msg, justify='center'), expand=True, padding=(1, 1), style=style)
287
296
  panel = Align.center(panel) if is_centered else panel
288
- console.print(Padding(panel, (3, 0, 1, 0)))
297
+ console.print(Padding(panel, (3, 2, 1, 2)))
289
298
 
290
299
 
291
300
  def print_starred_header(msg: str, num_stars: int = 7, num_spaces: int = 2, style: str = TITLE_STYLE) -> None:
@@ -198,7 +198,7 @@ def write_word_counts_html() -> None:
198
198
  word_count = WordCount()
199
199
 
200
200
  # Remove dupes, junk mail, and fwded articles from emails
201
- emails = [e for e in epstein_files.emails if not (e.is_duplicate() or e.is_junk_mail() or e.is_fwded_article())]
201
+ emails = [e for e in epstein_files.non_duplicate_emails() if not (e.is_junk_mail() or e.is_fwded_article())]
202
202
 
203
203
  for email in emails:
204
204
  if specified_names and email.author not in specified_names:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epstein-files
3
- Version: 1.0.12
3
+ Version: 1.0.14
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
@@ -43,11 +43,12 @@ Description-Content-Type: text/markdown
43
43
 
44
44
 
45
45
  ## Usage
46
-
47
46
  #### Installation
48
47
  1. Requires you have a local copy of the OCR text files from the House Oversight document release in a directory `/path/to/epstein/ocr_txt_files`. You can download those OCR text files from [the Congressional Google Drive folder](https://drive.google.com/drive/folders/1ldncvdqIf6miiskDp_EDuGSDAaI_fJx8) (make sure you grab both the `001/` and `002/` folders).
49
48
  1. Use `poetry install` for easiest time installing. `pip install epstein-files` should also work, though `pipx install epstein-files` is usually better.
50
49
 
50
+
51
+ #### Command Line Tools
51
52
  You need to set the `EPSTEIN_DOCS_DIR` environment variable with the path to the folder of files you just downloaded when running. You can either create a `.env` file modeled on [`.env.example`](./.env.example) (which will set it permanently) or you can run with:
52
53
 
53
54
  ```bash
@@ -63,7 +64,7 @@ epstein_generate
63
64
  # Search for a string:
64
65
  epstein_search Bannon
65
66
  # Or a regex:
66
- epstein_search '\bSteve\s*Bannon\b'
67
+ epstein_search '\bSteve\s*Bannon|Jeffrey\s*Epstein\b'
67
68
 
68
69
  # Show a file with color highlighting of keywords:
69
70
  epstein_show 030999
@@ -82,6 +83,12 @@ epstein_diff 030999 020442
82
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.
83
84
  Run `epstein_generate --help` for command line option assistance.
84
85
 
86
+ **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:
87
+
88
+ ```bash
89
+ cp ./emails_extracted_from_legal_filings/*.txt "$EPSTEIN_DOCS_DIR"
90
+ ```
91
+
85
92
 
86
93
  #### As A Library
87
94
  ```python
@@ -0,0 +1,33 @@
1
+ epstein_files/__init__.py,sha256=9mClHe3YkTWHulLOZIO2uaxYcff-krpEsc0vphYlwps,4975
2
+ epstein_files/documents/communication.py,sha256=oqNsSDWe-N0jSmchIHxpihihzIWha-foFqMwKZlxyng,2057
3
+ epstein_files/documents/document.py,sha256=1qL1V5VrrtI7uuuLvOw-JU83khRzzEURduuoh_pfghI,17114
4
+ epstein_files/documents/email.py,sha256=eKfDGwbP1nYVfhozM0bSVf-5T-_l_k-0D_HVrQldm38,40904
5
+ epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
+ epstein_files/documents/imessage/text_message.py,sha256=JPHlO-5Xgt5V5E9fDsgCEr3XOp7FyzlhIHmZhFNZcmg,2806
7
+ epstein_files/documents/json_file.py,sha256=WcZW5NNqA67rHTdopbOGtup00muNaLlvrNgKb-K4zO8,1504
8
+ epstein_files/documents/messenger_log.py,sha256=le-cj_ZBDUb_jnxP_F05KlnPjh0nDbgpPSWl4-HL-J4,6502
9
+ epstein_files/documents/other_file.py,sha256=tJmEH3cGeEcRIZW5F-RuSJprYM_2r1jEbsF_kjSsA3E,9788
10
+ epstein_files/epstein_files.py,sha256=aO2vntbA7DonSk96xB5us5VaDSpp79Mpu8eYJ_g_8Qo,20025
11
+ epstein_files/util/constant/common_words.py,sha256=aR0UjoWmxyR49XS-DtHECQ1CiA_bK8hNP6CQ1TS9yZA,3696
12
+ epstein_files/util/constant/html.py,sha256=9U098TGzlghGg4WfxLYHyub5JGR17Dv7VP5i2MSu8Kk,1415
13
+ epstein_files/util/constant/names.py,sha256=smC9xsR9E9WECXi_ygK_6lrcEPZWZINLZrp_-BthUtA,10377
14
+ epstein_files/util/constant/output_files.py,sha256=BkV4_gmdj46RfGy5SFYp6dgTty3FtlBth5YGmaGutls,1700
15
+ epstein_files/util/constant/strings.py,sha256=etCmLZPuriVYDap4iG_0Nfd92P1cvRpK2R7ZpVAGDrw,1942
16
+ epstein_files/util/constant/urls.py,sha256=EKzpL1np3cdyYvUlgv1zl9IJU8Vrg8jXpAu6YpM0_Bk,5283
17
+ epstein_files/util/constants.py,sha256=W-4ibPdv8I62uNyoBUR7sWWiqUWWr2n414WnZNA_Who,112605
18
+ epstein_files/util/data.py,sha256=JccGFZGiCGm7XtwpQTocIjGYOr6hTUpEPwHhjyW9Xnc,3164
19
+ epstein_files/util/doc_cfg.py,sha256=uVUgZF7p5QMhbPEVauQWlRWQRhP0Imr5XaNQtMk0E7c,9053
20
+ epstein_files/util/env.py,sha256=zg-TJ8ea6nTa0PyYgY97Zksre8au1ELv2i8vOizZt7Y,5645
21
+ epstein_files/util/file_helper.py,sha256=tacTe1GcAnckPFvjMgxRRSLnFgr2aVIYsgfDR_C9uXk,2780
22
+ epstein_files/util/highlighted_group.py,sha256=mNcdML0h88e2voEiUJxpgAVXHh3jQ8f0XV8qVdZMkBM,36550
23
+ epstein_files/util/logging.py,sha256=fuREq06xUUI3DfCV2JE-8QM-sQKxpLDj0_AYFO6qR1M,1983
24
+ epstein_files/util/output.py,sha256=bb_-jRoFNNMHXPSaptEXdkbqNDJYOpNSs6dkJKvi_HQ,7581
25
+ epstein_files/util/rich.py,sha256=bQPlOEZ6qTpVF4yPnwmlBk4K11zH5RJjwbWeBIOUUGE,15191
26
+ epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
27
+ epstein_files/util/timer.py,sha256=8hxW4Y1JcTUfnBrHh7sL2pM9xu1sL4HFQM4CmmzTarU,837
28
+ epstein_files/util/word_count.py,sha256=dTBNqX98sj7W46O0uit76I4hYBhm0bsY1Q7RHwWehiU,9349
29
+ epstein_files-1.0.14.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
+ epstein_files-1.0.14.dist-info/METADATA,sha256=AUw8p6SQuvkJONsHErig0L--FyAU2y892DYpdpimqtg,5867
31
+ epstein_files-1.0.14.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
+ epstein_files-1.0.14.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
+ epstein_files-1.0.14.dist-info/RECORD,,
@@ -1,33 +0,0 @@
1
- epstein_files/__init__.py,sha256=qVFB7sS6XSlZX-ByyDwdbGSn2h06aoX2Mx8WcgRb-To,4710
2
- epstein_files/documents/communication.py,sha256=XapJlNfcaww3TpSkZIBE5c1Skqv_pFEFlIVi06V7k3E,2046
3
- epstein_files/documents/document.py,sha256=2FxyqWKROi7w2SmaQ493oGKekNvYAHSuv2YsDhPNQBU,16987
4
- epstein_files/documents/email.py,sha256=y8QTq349LWlm2LLUJ8rGcdkDbaGYJCV99wJytPcEMew,40587
5
- epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
- epstein_files/documents/imessage/text_message.py,sha256=4gFvTfulj_Su10lNQl6Hq_p9ArTrSmn5pfC22YRJXjI,2794
7
- epstein_files/documents/json_file.py,sha256=tIYTwA3FYkwVZSpXvFYyUoH9m2sGYCD1U0ttamH6r1o,1306
8
- epstein_files/documents/messenger_log.py,sha256=yT4WQyTE_W6yelug_YGpBMRJ0YxWNtX4rKoEj8n5TMA,6260
9
- epstein_files/documents/other_file.py,sha256=pnl_q1o7ur3eeqGPwsYL2qbM3Y8O9LX6j6LbWnoxAiE,9939
10
- epstein_files/epstein_files.py,sha256=SaD4DJJ5tRxY97Ei4BdOgLzHQ9wrBVGrP64CSqdmk-w,18691
11
- epstein_files/util/constant/common_words.py,sha256=aR0UjoWmxyR49XS-DtHECQ1CiA_bK8hNP6CQ1TS9yZA,3696
12
- epstein_files/util/constant/html.py,sha256=9U098TGzlghGg4WfxLYHyub5JGR17Dv7VP5i2MSu8Kk,1415
13
- epstein_files/util/constant/names.py,sha256=CLWXrln8J-Dth6C-YF7Wdy7UoA8dybKJyqOLETrBeek,10284
14
- epstein_files/util/constant/output_files.py,sha256=BkV4_gmdj46RfGy5SFYp6dgTty3FtlBth5YGmaGutls,1700
15
- epstein_files/util/constant/strings.py,sha256=02DwbhAe8qBRq5HOUFx5FafXJ1P2-RJf9TCVu2b7UDQ,1932
16
- epstein_files/util/constant/urls.py,sha256=0IdCVVvXib0i-4TZFkVHoS4zCbjOBZWcr6NkGxsmQWM,4981
17
- epstein_files/util/constants.py,sha256=BpPRivoDYFI0uLU35kKpOdrSI6Rr9cmcrRj9-kANVrs,111834
18
- epstein_files/util/data.py,sha256=X3AutdW-ascIlE2bz1BtN0Bywqpe4OwYzJ-diEpfogI,2992
19
- epstein_files/util/doc_cfg.py,sha256=_f03qtA7qVbViHwqMXC4O5nfNbh90zDSq6El9Ior6f0,8996
20
- epstein_files/util/env.py,sha256=HnYcfHSNkwVJ_T75Woy43_OpDyxD0KHPj3GxcVx86N4,5751
21
- epstein_files/util/file_helper.py,sha256=tacTe1GcAnckPFvjMgxRRSLnFgr2aVIYsgfDR_C9uXk,2780
22
- epstein_files/util/highlighted_group.py,sha256=xrDLB05YUYGsU6vDvhvENMvIyjEz-9eb9xN-RjfCQbQ,36531
23
- epstein_files/util/logging.py,sha256=fuREq06xUUI3DfCV2JE-8QM-sQKxpLDj0_AYFO6qR1M,1983
24
- epstein_files/util/output.py,sha256=XcflgSOlzUGj6FsFaK6j4Dljld8A0h_uVV7ERcI_EYw,8120
25
- epstein_files/util/rich.py,sha256=8-4IA5bwPBdDPqkPdymq3zVKB9hfy3nrT7fUrN_XevY,14744
26
- epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
27
- epstein_files/util/timer.py,sha256=8hxW4Y1JcTUfnBrHh7sL2pM9xu1sL4HFQM4CmmzTarU,837
28
- epstein_files/util/word_count.py,sha256=8qBTuq3d0Q-3fwiuECKWi2RfL-KUiZD8TciwvfL0D_o,9353
29
- epstein_files-1.0.12.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
- epstein_files-1.0.12.dist-info/METADATA,sha256=imTDdrHjWC-bWuw58SAyjYyiziZsqHkO7ODQUntw6YQ,5480
31
- epstein_files-1.0.12.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
- epstein_files-1.0.12.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
- epstein_files-1.0.12.dist-info/RECORD,,