epstein-files 1.0.0__py3-none-any.whl → 1.0.2__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.
Files changed (32) hide show
  1. epstein_files/__init__.py +75 -135
  2. epstein_files/documents/communication.py +9 -9
  3. epstein_files/documents/document.py +115 -87
  4. epstein_files/documents/email.py +154 -85
  5. epstein_files/documents/emails/email_header.py +7 -6
  6. epstein_files/documents/imessage/text_message.py +3 -2
  7. epstein_files/documents/json_file.py +17 -0
  8. epstein_files/documents/messenger_log.py +62 -3
  9. epstein_files/documents/other_file.py +165 -17
  10. epstein_files/epstein_files.py +128 -169
  11. epstein_files/util/constant/names.py +8 -1
  12. epstein_files/util/constant/output_files.py +29 -0
  13. epstein_files/util/constant/strings.py +27 -0
  14. epstein_files/util/constant/urls.py +25 -9
  15. epstein_files/util/constants.py +1018 -1045
  16. epstein_files/util/data.py +20 -55
  17. epstein_files/util/{file_cfg.py → doc_cfg.py} +121 -43
  18. epstein_files/util/env.py +19 -20
  19. epstein_files/util/file_helper.py +38 -21
  20. epstein_files/util/highlighted_group.py +229 -177
  21. epstein_files/util/logging.py +63 -0
  22. epstein_files/util/output.py +180 -0
  23. epstein_files/util/rich.py +29 -17
  24. epstein_files/util/search_result.py +14 -6
  25. epstein_files/util/timer.py +24 -0
  26. epstein_files/util/word_count.py +2 -1
  27. {epstein_files-1.0.0.dist-info → epstein_files-1.0.2.dist-info}/METADATA +20 -4
  28. epstein_files-1.0.2.dist-info/RECORD +33 -0
  29. epstein_files-1.0.2.dist-info/entry_points.txt +7 -0
  30. epstein_files-1.0.0.dist-info/RECORD +0 -28
  31. {epstein_files-1.0.0.dist-info → epstein_files-1.0.2.dist-info}/LICENSE +0 -0
  32. {epstein_files-1.0.0.dist-info → epstein_files-1.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,63 @@
1
+ import logging
2
+ from os import environ
3
+ from pathlib import Path
4
+
5
+ from rich.console import Console
6
+ from rich.highlighter import ReprHighlighter
7
+ from rich.logging import RichHandler
8
+ from rich.theme import Theme
9
+
10
+ from epstein_files.util.constant.strings import *
11
+ from epstein_files.util.file_helper import file_size_str
12
+
13
+ FILENAME_STYLE = 'gray27'
14
+
15
+ DOC_TYPE_STYLES = {
16
+ DOCUMENT_CLASS: 'grey69',
17
+ EMAIL_CLASS: 'dark_orange3',
18
+ JSON_FILE_CLASS: 'sandy_brown',
19
+ MESSENGER_LOG_CLASS: 'deep_pink4',
20
+ OTHER_FILE_CLASS: 'grey69',
21
+ }
22
+
23
+ LOG_THEME = {
24
+ f"{ReprHighlighter.base_style}{doc_type}": f"{doc_style} bold"
25
+ for doc_type, doc_style in DOC_TYPE_STYLES.items()
26
+ }
27
+
28
+ LOG_THEME[f"{ReprHighlighter.base_style}epstein_filename"] = FILENAME_STYLE
29
+ LOG_LEVEL_ENV_VAR = 'LOG_LEVEL'
30
+
31
+
32
+ class LogHighlighter(ReprHighlighter):
33
+ highlights = ReprHighlighter.highlights + [
34
+ *[fr"(?P<{doc_type}>{doc_type})" for doc_type in DOC_TYPE_STYLES.keys()],
35
+ "(?P<epstein_filename>" + FILE_NAME_REGEX.pattern + ')',
36
+ ]
37
+
38
+
39
+ log_console = Console(color_system='256', theme=Theme(LOG_THEME))
40
+ log_handler = RichHandler(console=log_console, highlighter=LogHighlighter())
41
+ logging.basicConfig(level="NOTSET", format="%(message)s", datefmt="[%X]", handlers=[log_handler])
42
+ logger = logging.getLogger("rich")
43
+
44
+
45
+ # Log levels
46
+ datefinder_logger = logging.getLogger('datefinder') # Set log level to suppress annoying output
47
+ env_log_level_str = environ.get(LOG_LEVEL_ENV_VAR) or None
48
+ env_log_level = None
49
+
50
+ if env_log_level_str:
51
+ try:
52
+ env_log_level = getattr(logging, env_log_level_str)
53
+ except Exception as e:
54
+ logger.warning(f"{LOG_LEVEL_ENV_VAR}='{env_log_level_str}' does not exist, defaulting to DEBUG")
55
+ env_log_level = logging.DEBUG
56
+
57
+ logger.warning(f"Setting log level to {env_log_level} based on {LOG_LEVEL_ENV_VAR} env var...")
58
+ logger.setLevel(env_log_level)
59
+ datefinder_logger.setLevel(env_log_level)
60
+
61
+
62
+ def log_file_write(file_path: str | Path) -> None:
63
+ logger.warning(f"Wrote {file_size_str(file_path)} to '{file_path}'")
@@ -0,0 +1,180 @@
1
+ from rich.padding import Padding
2
+
3
+ from epstein_files.documents.email import Email
4
+ from epstein_files.documents.messenger_log import MessengerLog
5
+ from epstein_files.epstein_files import EpsteinFiles, count_by_month
6
+ from epstein_files.util.constant.output_files import JSON_METADATA_PATH
7
+ from epstein_files.util.constant import urls
8
+ from epstein_files.util.constant.html import *
9
+ from epstein_files.util.constant.names import *
10
+ from epstein_files.util.constant.strings import EMAIL_CLASS, MESSENGER_LOG_CLASS
11
+ from epstein_files.util.data import dict_sets_to_lists
12
+ from epstein_files.util.env import args, specified_names
13
+ from epstein_files.util.logging import log_file_write, logger
14
+ from epstein_files.util.rich import *
15
+
16
+ PRINT_COLOR_KEY_EVERY_N_EMAILS = 150
17
+
18
+ # Order matters. Default names to print emails for.
19
+ DEFAULT_EMAILERS = [
20
+ JEREMY_RUBIN,
21
+ AL_SECKEL,
22
+ JOI_ITO,
23
+ JABOR_Y,
24
+ STEVEN_SINOFSKY,
25
+ DANIEL_SIAD,
26
+ JEAN_LUC_BRUNEL,
27
+ STEVEN_HOFFENBERG,
28
+ EHUD_BARAK,
29
+ MARTIN_NOWAK,
30
+ MASHA_DROKOVA,
31
+ RENATA_BOLOTOVA,
32
+ STEVE_BANNON,
33
+ OLIVIER_COLOM,
34
+ BORIS_NIKOLIC,
35
+ PRINCE_ANDREW,
36
+ JIDE_ZEITLIN,
37
+ DAVID_STERN,
38
+ MOHAMED_WAHEED_HASSAN,
39
+ JENNIFER_JACQUET,
40
+ TYLER_SHEARS,
41
+ CHRISTINA_GALBRAITH,
42
+ None,
43
+ ]
44
+
45
+ # Order matters. Default names to print tables w/email subject, timestamp, etc for. # TODO: get rid of this ?
46
+ DEFAULT_EMAILER_TABLES: list[str | None] = [
47
+ GHISLAINE_MAXWELL,
48
+ LEON_BLACK,
49
+ SULTAN_BIN_SULAYEM,
50
+ DEEPAK_CHOPRA,
51
+ ARIANE_DE_ROTHSCHILD,
52
+ ]
53
+
54
+ if len(set(DEFAULT_EMAILERS).intersection(set(DEFAULT_EMAILER_TABLES))) > 0:
55
+ raise RuntimeError(f"Some names appear in both DEFAULT_EMAILERS and DEFAULT_EMAILER_TABLES")
56
+
57
+
58
+ def print_emails(epstein_files: EpsteinFiles) -> int:
59
+ """Returns number of emails printed."""
60
+ print_section_header(('Selections from ' if not args.all_emails else '') + 'His Emails')
61
+ print_other_site_link(is_header=False)
62
+
63
+ emailers_to_print: list[str | None]
64
+ emailer_tables: list[str | None] = []
65
+ already_printed_emails: list[Email] = []
66
+ num_emails_printed_since_last_color_key = 0
67
+
68
+ if specified_names:
69
+ emailers_to_print = specified_names
70
+ else:
71
+ epstein_files.print_emailer_counts_table()
72
+
73
+ if args.all_emails:
74
+ emailers_to_print = sorted(epstein_files.all_emailers(), key=lambda e: epstein_files.earliest_email_at(e))
75
+ console.print('Email conversations are sorted chronologically based on time of the first email.')
76
+ print_numbered_list_of_emailers(emailers_to_print, epstein_files)
77
+ else:
78
+ emailers_to_print = DEFAULT_EMAILERS
79
+ emailer_tables = DEFAULT_EMAILER_TABLES
80
+ console.print('Email conversations grouped by counterparty can be found in the order listed below.')
81
+ print_numbered_list_of_emailers(emailers_to_print)
82
+ console.print("\nAfter that there's tables linking to (but not displaying) all known emails for each of these people:")
83
+ print_numbered_list_of_emailers(emailer_tables)
84
+
85
+ for author in emailers_to_print:
86
+ author_emails = epstein_files.print_emails_for(author)
87
+ already_printed_emails.extend(author_emails)
88
+ num_emails_printed_since_last_color_key += len(author_emails)
89
+
90
+ # Print color key every once in a while
91
+ if num_emails_printed_since_last_color_key > PRINT_COLOR_KEY_EVERY_N_EMAILS:
92
+ print_color_key()
93
+ num_emails_printed_since_last_color_key = 0
94
+
95
+ if emailer_tables:
96
+ print_author_header(f"Email Tables for {len(emailer_tables)} Other People", 'white')
97
+
98
+ for name in DEFAULT_EMAILER_TABLES:
99
+ epstein_files.print_emails_table_for(name)
100
+
101
+ if not specified_names:
102
+ epstein_files.print_email_device_info()
103
+
104
+ if args.all_emails:
105
+ _verify_all_emails_printed(epstein_files, already_printed_emails)
106
+
107
+ logger.warning(f"Rewrote {len(Email.rewritten_header_ids)} headers of {len(epstein_files.emails)} emails")
108
+ return len(already_printed_emails)
109
+
110
+
111
+ def print_json_metadata(epstein_files: EpsteinFiles) -> None:
112
+ json_str = epstein_files.json_metadata()
113
+
114
+ if args.build:
115
+ with open(JSON_METADATA_PATH, 'w') as f:
116
+ f.write(json_str)
117
+ log_file_write(JSON_METADATA_PATH)
118
+ else:
119
+ console.print_json(json_str, indent=4, sort_keys=True)
120
+
121
+
122
+ def print_json_stats(epstein_files: EpsteinFiles) -> None:
123
+ console.line(5)
124
+ console.print(Panel('JSON Stats Dump', expand=True, style='reverse bold'), '\n')
125
+ print_json(f"{MESSENGER_LOG_CLASS} Sender Counts", MessengerLog.count_authors(epstein_files.imessage_logs), skip_falsey=True)
126
+ print_json(f"{EMAIL_CLASS} Author Counts", epstein_files.email_author_counts, skip_falsey=True)
127
+ print_json(f"{EMAIL_CLASS} Recipient Counts", epstein_files.email_recipient_counts, skip_falsey=True)
128
+ print_json("Email signature_substitution_countss", epstein_files.email_signature_substitution_counts(), skip_falsey=True)
129
+ print_json("email_author_device_signatures", dict_sets_to_lists(epstein_files.email_authors_to_device_signatures))
130
+ print_json("email_sent_from_devices", dict_sets_to_lists(epstein_files.email_device_signatures_to_authors))
131
+ print_json("email_unknown_recipient_file_ids", epstein_files.email_unknown_recipient_file_ids())
132
+ print_json("count_by_month", count_by_month(epstein_files.all_documents()))
133
+
134
+
135
+ def print_text_messages(epstein_files: EpsteinFiles) -> None:
136
+ print_section_header('Text Messages')
137
+ print_centered("(conversations are sorted chronologically based on timestamp of first message)\n", style='gray30')
138
+ authors: list[str | None] = specified_names if specified_names else [JEFFREY_EPSTEIN]
139
+ log_files = epstein_files.imessage_logs_for(authors)
140
+
141
+ for log_file in log_files:
142
+ console.print(Padding(log_file))
143
+ console.line(2)
144
+
145
+ epstein_files.print_imessage_summary()
146
+
147
+
148
+ def write_urls() -> None:
149
+ if args.output_file == 'index.html':
150
+ logger.warning(f"Can't write env vars to '{args.output_file}', writing to '{URLS_ENV}' instead.\n")
151
+ args.output_file = URLS_ENV
152
+
153
+ url_vars = {
154
+ k: v for k, v in vars(urls).items()
155
+ if isinstance(v, str) and \
156
+ k.split('_')[-1] in ['URL'] and \
157
+ 'michelcrypt4d4mus' in v and \
158
+ 'github.com' not in v and \
159
+ 'BASE' not in v
160
+ }
161
+
162
+ with open(args.output_file, 'w') as f:
163
+ for var_name, url in url_vars.items():
164
+ key_value = f"{var_name}='{url}'"
165
+ console.print(key_value, style='dim')
166
+ f.write(f"{key_value}\n")
167
+
168
+ console.line()
169
+ logger.warning(f"Wrote {len(url_vars)} URL variables to '{args.output_file}'\n")
170
+
171
+
172
+
173
+ def _verify_all_emails_printed(epstein_files: EpsteinFiles, already_printed_emails: list[Email]) -> None:
174
+ """Log warnings if some emails were never printed."""
175
+ email_ids_that_were_printed = set([email.file_id for email in already_printed_emails])
176
+ logger.warning(f"Printed {len(already_printed_emails)} emails of {len(email_ids_that_were_printed)} unique file IDs.")
177
+
178
+ for email in epstein_files.emails:
179
+ if email.file_id not in email_ids_that_were_printed and not email.is_duplicate:
180
+ logger.warning(f"Failed to print {email.summary()}")
@@ -2,7 +2,6 @@
2
2
  import json
3
3
  from os import devnull
4
4
  from pathlib import Path
5
- from typing import Literal
6
5
 
7
6
  from rich.align import Align
8
7
  from rich.console import Console, RenderableType
@@ -18,9 +17,10 @@ from epstein_files.util.constant.names import UNKNOWN
18
17
  from epstein_files.util.constant.strings import DEFAULT, EMAIL, NA, OTHER_SITE_LINK_STYLE, QUESTION_MARKS, SiteType
19
18
  from epstein_files.util.constant.urls import *
20
19
  from epstein_files.util.constants import FALLBACK_TIMESTAMP, HEADER_ABBREVIATIONS
21
- from epstein_files.util.env import args, logger
22
- from epstein_files.util.file_helper import file_size_str
23
- from epstein_files.util.highlighted_group import HIGHLIGHTED_GROUPS, InterestingNamesHighlighter
20
+ from epstein_files.util.data import json_safe
21
+ from epstein_files.util.env import args
22
+ from epstein_files.util.highlighted_group import ALL_HIGHLIGHTS, HIGHLIGHTED_NAMES, EpsteinHighlighter
23
+ from epstein_files.util.logging import log_file_write, logger
24
24
 
25
25
  TITLE_WIDTH = 50
26
26
  NUM_COLOR_KEY_COLS = 4
@@ -38,20 +38,19 @@ TITLE_STYLE = 'black on bright_white bold'
38
38
 
39
39
  HIGHLIGHTED_GROUP_COLOR_KEYS = [
40
40
  Text(highlight_group.label.replace('_', ' '), style=highlight_group.style)
41
- for highlight_group in sorted(HIGHLIGHTED_GROUPS, key=lambda hg: hg.label)
42
- if not highlight_group.is_multiline
41
+ for highlight_group in sorted(HIGHLIGHTED_NAMES, key=lambda hg: hg.label)
43
42
  ]
44
43
 
45
44
  THEME_STYLES = {
46
45
  DEFAULT: 'wheat4',
47
46
  TEXT_LINK: 'deep_sky_blue4 underline',
48
- **{hg.theme_style_name: hg.style for hg in HIGHLIGHTED_GROUPS}, # Inject style names for HighlightedGroups
47
+ **{hg.theme_style_name: hg.style for hg in ALL_HIGHLIGHTS},
49
48
  }
50
49
 
51
50
  # Instantiate console object
52
51
  CONSOLE_ARGS = {
53
52
  'color_system': '256',
54
- 'highlighter': InterestingNamesHighlighter(),
53
+ 'highlighter': EpsteinHighlighter(),
55
54
  'record': args.build,
56
55
  'safe_box': False,
57
56
  'theme': Theme(THEME_STYLES),
@@ -72,6 +71,14 @@ def add_cols_to_table(table: Table, col_names: list[str]) -> None:
72
71
  table.add_column(col, justify='left' if i == 0 else 'center')
73
72
 
74
73
 
74
+ def build_highlighter(pattern: str) -> EpsteinHighlighter:
75
+ class TempHighlighter(EpsteinHighlighter):
76
+ """rich.highlighter that finds and colors interesting keywords based on the above config."""
77
+ highlights = EpsteinHighlighter.highlights + [re.compile(fr"(?P<trump>{pattern})", re.IGNORECASE)]
78
+
79
+ return TempHighlighter()
80
+
81
+
75
82
  def join_texts(txts: list[Text], join: str = ' ', encloser: str = '') -> Text:
76
83
  """Join rich.Text objs into one."""
77
84
  if encloser:
@@ -90,8 +97,11 @@ def join_texts(txts: list[Text], join: str = ' ', encloser: str = '') -> Text:
90
97
  return txt
91
98
 
92
99
 
93
- def key_value_txt(key: str, value: Text | str) -> Text:
100
+ def key_value_txt(key: str, value: Text | int | str) -> Text:
94
101
  """Generate a Text obj for 'key=value'."""
102
+ if isinstance(value, int):
103
+ value = Text(f"{value}", style='cyan')
104
+
95
105
  return Text('').append(key, style=KEY_STYLE).append('=', style=SYMBOL_STYLE).append(value)
96
106
 
97
107
 
@@ -121,7 +131,7 @@ def print_centered_link(url: str, link_text: str, style: str | None = None) -> N
121
131
  print_centered(link_markup(url, link_text, style or ARCHIVE_LINK_COLOR))
122
132
 
123
133
 
124
- def print_color_key(_key_type: Literal["Groups", "People"] = "Groups") -> None:
134
+ def print_color_key() -> None:
125
135
  color_table = Table(title=f'Rough Guide to Highlighted Colors', show_header=False)
126
136
  num_colors = len(HIGHLIGHTED_GROUP_COLOR_KEYS)
127
137
  row_number = 0
@@ -153,13 +163,13 @@ def print_header(epstein_files: 'EpsteinFiles') -> None:
153
163
 
154
164
 
155
165
  def print_json(label: str, obj: object, skip_falsey: bool = False) -> None:
166
+ print(obj)
167
+
156
168
  if isinstance(obj, dict):
157
169
  if skip_falsey:
158
170
  obj = {k: v for k, v in obj.items() if v}
159
171
 
160
- if None in obj:
161
- obj = {k or UNKNOWN: v for k, v in obj.items()}
162
-
172
+ obj = json_safe(obj)
163
173
 
164
174
  console.line()
165
175
  console.print(Panel(label, expand=False))
@@ -218,6 +228,8 @@ def print_other_site_link(is_header: bool = True) -> None:
218
228
  print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
219
229
  word_count_link = link_text_obj(WORD_COUNT_URL, 'site showing the most frequently used words in these communiques', OTHER_SITE_LINK_STYLE)
220
230
  print_centered(parenthesize(word_count_link))
231
+ metadata_link = link_text_obj(JSON_METADATA_URL, 'metadata with author attribution explanations', OTHER_SITE_LINK_STYLE)
232
+ print_centered(parenthesize(metadata_link))
221
233
 
222
234
 
223
235
  def print_page_title(expand: bool = True, width: int | None = None) -> None:
@@ -292,8 +304,8 @@ def write_html(output_path: Path) -> None:
292
304
  logger.warning(f"Not writing HTML because args.build={args.build}.")
293
305
  return
294
306
 
295
- console.save_html(output_path, code_format=CONSOLE_HTML_FORMAT, theme=HTML_TERMINAL_THEME)
296
- logger.warning(f"Wrote {file_size_str(output_path)} to '{output_path}'")
307
+ console.save_html(str(output_path), code_format=CONSOLE_HTML_FORMAT, theme=HTML_TERMINAL_THEME)
308
+ log_file_write(output_path)
297
309
 
298
310
 
299
311
  def _print_abbreviations_table() -> None:
@@ -320,5 +332,5 @@ def _print_external_links() -> None:
320
332
  print_centered(link_markup(EPSTEIN_WEB_URL) + " (character summaries)")
321
333
 
322
334
 
323
- if args.deep_debug:
324
- print_json('THEME_STYLES', THEME_STYLES)
335
+ # if args.deep_debug:
336
+ # print_json('THEME_STYLES', THEME_STYLES)
@@ -1,15 +1,23 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
  from rich.text import Text
4
+ # from epstein_files.documents.document import type Document
4
5
 
5
- from epstein_files.documents.document import Document
6
+
7
+ @dataclass
8
+ class MatchedLine:
9
+ line: str
10
+ line_number: int
11
+
12
+ def __rich__(self) -> Text:
13
+ return Text('').append(str(self.line_number), style='cyan').append(f":{self.line}")
14
+
15
+ def __str__(self) -> str:
16
+ return f"{self.line_number}:{self.line}"
6
17
 
7
18
 
8
19
  @dataclass
9
20
  class SearchResult:
10
21
  """Simple class used for collecting documents that match a given search term."""
11
- document: Document
12
- lines: list[Text] # The lines that match the search
13
-
14
- def unprefixed_lines(self) -> list[str]:
15
- return [line.plain.split(':', 1)[1] for line in self.lines]
22
+ document: 'Document'
23
+ lines: list[MatchedLine]
@@ -0,0 +1,24 @@
1
+ import time
2
+ from dataclasses import dataclass, field
3
+
4
+ from epstein_files.util.logging import logger
5
+
6
+
7
+ @dataclass
8
+ class Timer:
9
+ started_at: float = field(default_factory=lambda: time.perf_counter())
10
+ checkpoint_at: float = field(default_factory=lambda: time.perf_counter())
11
+ decimals: int = 2
12
+
13
+ def print_at_checkpoint(self, msg: str) -> None:
14
+ logger.warning(f"{msg} in {self.seconds_since_checkpoint_str()}")
15
+ self.checkpoint_at = time.perf_counter()
16
+
17
+ def seconds_since_checkpoint_str(self) -> str:
18
+ return f"{(time.perf_counter() - self.checkpoint_at):.{self.decimals}f} seconds"
19
+
20
+ def seconds_since_start(self) -> float:
21
+ return time.perf_counter() - self.started_at
22
+
23
+ def seconds_since_start_str(self) -> str:
24
+ return f"{self.seconds_since_start():.{self.decimals}f} seconds"
@@ -12,7 +12,8 @@ from epstein_files.documents.emails.email_header import EmailHeader
12
12
  from epstein_files.util.constant.common_words import COMMON_WORDS, UNSINGULARIZABLE_WORDS
13
13
  from epstein_files.util.constant.names import OTHER_NAMES
14
14
  from epstein_files.util.data import ALL_NAMES, flatten, sort_dict
15
- from epstein_files.util.env import args, logger
15
+ from epstein_files.util.env import args
16
+ from epstein_files.util.logging import logger
16
17
  from epstein_files.util.rich import highlighter
17
18
  from epstein_files.util.search_result import SearchResult
18
19
 
@@ -1,26 +1,42 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epstein-files
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Tools for working with the Jeffrey Epstein documents released in November 2025.
5
+ Home-page: https://michelcrypt4d4mus.github.io/epstein_text_messages/
6
+ License: GPL-3.0-or-later
7
+ Keywords: Epstein,Jeffrey Epstein
5
8
  Author: Michel de Cryptadamus
6
9
  Requires-Python: >=3.11,<4.0
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
+ Classifier: Programming Language :: Python
7
15
  Classifier: Programming Language :: Python :: 3
8
16
  Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
9
20
  Requires-Dist: datefinder (>=0.7.3,<0.8.0)
10
21
  Requires-Dist: inflection (>=0.5.1,<0.6.0)
11
22
  Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
12
23
  Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
13
24
  Requires-Dist: requests (>=2.32.5,<3.0.0)
14
25
  Requires-Dist: rich (>=14.2.0,<15.0.0)
26
+ Project-URL: Emails, https://michelcrypt4d4mus.github.io/epstein_text_messages/all_emails_epstein_files_nov_2025.html
27
+ Project-URL: Metadata, https://michelcrypt4d4mus.github.io/epstein_text_messages/file_metadata_epstein_files_nov_2025.json
28
+ Project-URL: TextMessages, https://michelcrypt4d4mus.github.io/epstein_text_messages
29
+ Project-URL: WordCounts, https://michelcrypt4d4mus.github.io/epstein_text_messages/communication_word_count_epstein_files_nov_2025.html
15
30
  Description-Content-Type: text/markdown
16
31
 
17
32
  # I Made Epstein's Text Messages Great Again
18
33
 
19
34
  * [I Made Epstein's Text Messages Great Again (And You Should Read Them)](https://cryptadamus.substack.com/p/i-made-epsteins-text-messages-great) post on [Substack](https://cryptadamus.substack.com/p/i-made-epsteins-text-messages-great)
20
35
  * The Epstein text messages (and some of the emails along with summary counts of sent emails to/from Epstein) generated by this code can be viewed [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/).
21
- * All of His Emails can be read at another page also generated by this code [here](https://michelcrypt4d4mus.github.io/epstein_emails_house_oversight/).
22
- * Word counts for the emails and text messages are [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/epstein_emails_word_count.html).
23
- * Configuration variables assigning specific `HOUSE_OVERSIGHT_XXXXXX.txt` file IDs (the `111111` part) as being emails to or from particular people based on various research and contributions can be found in the [constants.py](./epstein_files/util/constants.py) file in this repo.
36
+ * All of His Emails can be read at another page also generated by this code [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/all_emails_epstein_files_nov_2025.html).
37
+ * Word counts for the emails and text messages are [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/communication_word_count_epstein_files_nov_2025.html).
38
+ * Metadata containing what I have figured out about who sent or received the communications in a given file (and a brief explanation for how I figured it out for each file) is deployed [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/file_metadata_epstein_files_nov_2025.json)
39
+ * Configuration variables assigning specific `HOUSE_OVERSIGHT_XXXXXX.txt` file IDs (the `111111` part) as being emails to or from particular people based on various research and contributions can be found in [constants.py](./epstein_files/util/constants.py). Everything in `constants.py` should also appear in the JSON metadata.
24
40
 
25
41
 
26
42
  ### Usage
@@ -0,0 +1,33 @@
1
+ epstein_files/__init__.py,sha256=N4-A81KlSNWXyliBsjooi6GZr9_2qIB08qTG5RE9GzA,4725
2
+ epstein_files/documents/communication.py,sha256=SunZdjMhR9v6y8LlQ6jhIu8vYjSndaBK0Su1mKnhfj0,2060
3
+ epstein_files/documents/document.py,sha256=MOTS6AZFNOqnzpvYLXvoJC05ZVL9lTZnsRc-qjAjcJ4,16515
4
+ epstein_files/documents/email.py,sha256=IpKeOuLTmHWowBvUUEp-tyTC8pwEmXg3XgLJkplQZWg,37717
5
+ epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
+ epstein_files/documents/imessage/text_message.py,sha256=DMdd__L7UPad0YS49MJf_3bTVyE1BLfWafQbDQierC8,3272
7
+ epstein_files/documents/json_file.py,sha256=Vf9iHiEhUqk-hEh6lGZX_mJNWZUUQWeT-UI3FhKW0hw,1101
8
+ epstein_files/documents/messenger_log.py,sha256=-hSMFH_dyrjGLdph4SU2xQK4RpXOhkR3R_nqRrz3e1w,5620
9
+ epstein_files/documents/other_file.py,sha256=JbKDtNrQ1Ua5vGPlZayON5Kgy0oJ-gHcdO9l9Iv9wRo,8930
10
+ epstein_files/epstein_files.py,sha256=NpgQaxM3cC8CsAbzCyysakMbPdASWAt-wOhPZ879ZyQ,18018
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=g0s9NA4zIexDGG7u5x0KDpLB9fyrYaYatsBhf_lH688,10253
14
+ epstein_files/util/constant/output_files.py,sha256=B2qEXfNI_gT2Vp5HGSld2xM0PfeZ27j65HNymSmyzX4,974
15
+ epstein_files/util/constant/strings.py,sha256=3JTqD0luJrC3NbGXn4q6P-gIaaNVx36P1oCmp92gAoM,1750
16
+ epstein_files/util/constant/urls.py,sha256=x7Lv8yNNNLGU3GCvG4YbJ4qX3s_hiXffYuYUCjXyfbg,5526
17
+ epstein_files/util/constants.py,sha256=xME94iH9a4b95N4yABs20Gn3Tu3cwmx5kNE_fPhsJEM,103420
18
+ epstein_files/util/data.py,sha256=P4D_ggNNyScpTnu9wow8-67BlZtAXFKulJ5zbGtBR9A,2907
19
+ epstein_files/util/doc_cfg.py,sha256=6H5EFLxG0ABG4BJHIEL7PSMBVwkcyjH1vvmitSQRa48,9615
20
+ epstein_files/util/env.py,sha256=A2hEVg1HYymGd2odrLLo6k7yIvu0hh1XZniUW2u21dM,4734
21
+ epstein_files/util/file_helper.py,sha256=v_bE10MHEcXti9DVJo4WqyOsG83Xrv05S3Vc70cYJkk,3082
22
+ epstein_files/util/highlighted_group.py,sha256=7MfES52q10eq35L93iTIr_v5v0bamdQKCf7hlDIy7O8,35196
23
+ epstein_files/util/logging.py,sha256=GjmOYiWAF1R_0Dvb5kXHAgPH5UJs-_gGcRig7LEDDL0,2066
24
+ epstein_files/util/output.py,sha256=YH_-1YyNxiO29N88jvSAePbK5n25tgEIDFyP3sNNnnI,7309
25
+ epstein_files/util/rich.py,sha256=gvSbWc-PQC5cAUg8zn02yZQkU57ExG1ArRLMIPrVxOc,13597
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=XTINgLm01jFQlNgdiLCcVFCodXAIb1dNbaAvznoRb1o,6757
29
+ epstein_files-1.0.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
+ epstein_files-1.0.2.dist-info/METADATA,sha256=Wf4rPDzdGRxogbs0H8cZoFb7HsRTrkPvkYHdClbg74c,4653
31
+ epstein_files-1.0.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
+ epstein_files-1.0.2.dist-info/entry_points.txt,sha256=EV9qTh_n9X_1MOiQnxG5hM6R5v0rfi8W4QE-bsZkw3o,238
33
+ epstein_files-1.0.2.dist-info/RECORD,,
@@ -0,0 +1,7 @@
1
+ [console_scripts]
2
+ epstein_diff=epstein_files:epstein_diff
3
+ epstein_dump_urls=epstein_files:epstein_dump_urls
4
+ epstein_generate=epstein_files:generate_html
5
+ epstein_search=epstein_files:epstein_search
6
+ epstein_show=epstein_files:epstein_show
7
+
@@ -1,28 +0,0 @@
1
- epstein_files/__init__.py,sha256=JlGEliI8H5TqdGuCTtGIwLiM7GutbyND-IURG5Z-gAA,7442
2
- epstein_files/documents/communication.py,sha256=XybnJDqyK00RTeEkbLWgrVDkZS7pmC8EoftX1_G4OIM,2066
3
- epstein_files/documents/document.py,sha256=6av_KLTm70KIABl9Fl7DL9jKkvqdN18OLmECj2PAkEs,15223
4
- epstein_files/documents/email.py,sha256=rzgyVMBlKo9ytRdE6Eif_8zF4fecaMduIgPQkvRmmk0,34283
5
- epstein_files/documents/emails/email_header.py,sha256=JqcSqa-amdombgszE_cjXBrvZKE0HxU2mNAoD44Ekh4,7479
6
- epstein_files/documents/imessage/text_message.py,sha256=zU46FHeHKG6vbIZ-qLDdZC-1f3VmXW73fKo-BKOCgq8,3199
7
- epstein_files/documents/json_file.py,sha256=sL99E_34X9BIwQ27vE0Afy446oiyCmPLYdsJ6-OGMHU,611
8
- epstein_files/documents/messenger_log.py,sha256=HbtqthtkzXhkY7DxwxFOBy6xx6gPmmXIxZ4bsloLHEg,2995
9
- epstein_files/documents/other_file.py,sha256=_Z8EVLLy1u8RuEr5iPTKJdYZjQHFHp0o-mBErBYsRXg,4699
10
- epstein_files/epstein_files.py,sha256=Fb-SPwRlHZPB7iL48dL3Da4nPyzF9_Rk5nNpVnfku2U,20131
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=_iNHJsr4sdUXG1cozllRy8yV6SYXgsr6oTPHTCbrpj0,9967
14
- epstein_files/util/constant/strings.py,sha256=B5RpaGCc1EqiDKF-3BabNy4dJU6n4kXytx96aanHIDA,1115
15
- epstein_files/util/constant/urls.py,sha256=pks5frfWXmFwEkfB33Uy7IR1mn0DaAI_8kDjA_g03yg,5089
16
- epstein_files/util/constants.py,sha256=jErrj2r_K8pbFNih7WxlcP0sPO7ZyzrLxH3MlSw5xR4,106137
17
- epstein_files/util/data.py,sha256=7yz3osIlpjV9nbPEvRBmExokBsgm20kitSfqNpaYWj4,3746
18
- epstein_files/util/env.py,sha256=T-sd1lPfw-L6WXvpIv-cqGTqBfZvacZvniW1OKOdkrU,4624
19
- epstein_files/util/file_cfg.py,sha256=E7VVxVZ_cSN18HgI6q8e6UwTApMWuPC9qTqb3_tXCqs,7183
20
- epstein_files/util/file_helper.py,sha256=EHVRFxcWmc0RD1VUeLFCcmM-82c5FISIUBIwg4TodsY,2727
21
- epstein_files/util/highlighted_group.py,sha256=0MpzBYVaGfyUZQwFP7EVrLHDYU57qnnmNDC56gVxq2Q,33091
22
- epstein_files/util/rich.py,sha256=Z28-etKpZdc6aPxdmAxNe9ZvMWK28iubYASt50VxtJ4,13194
23
- epstein_files/util/search_result.py,sha256=5nkR-YzUiR52FmGIad_Uw0XaU2E_FfHZBHgc8dm3sAs,429
24
- epstein_files/util/word_count.py,sha256=L1T6zjShaPZo1ilpM0dSAT3X-EgaZ4YEigHNLxjKit4,6719
25
- epstein_files-1.0.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
26
- epstein_files-1.0.0.dist-info/METADATA,sha256=dGc412CXHc2EHOd0C7HuEa2qFQFh42dNbDw5CiH0Ny4,3239
27
- epstein_files-1.0.0.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
28
- epstein_files-1.0.0.dist-info/RECORD,,