threads-cleaner 0.2.2__tar.gz → 0.2.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threads-cleaner
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Bulk-delete your Threads posts and replies. Free, open-source, runs locally.
5
5
  Project-URL: Homepage, https://github.com/vincentmathis/threads-cleaner
6
6
  Project-URL: Repository, https://github.com/vincentmathis/threads-cleaner
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "threads-cleaner"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "Bulk-delete your Threads posts and replies. Free, open-source, runs locally."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -77,11 +77,14 @@ class BrowserDeleter:
77
77
  time.sleep(0.3)
78
78
  except: pass
79
79
  try:
80
- self._page.evaluate("document.querySelectorAll('[role=dialog]').forEach(e=>e.remove()); document.body.style.overflow='';")
80
+ self._page.keyboard.press("Escape")
81
+ time.sleep(0.3)
82
+ self._page.keyboard.press("Escape")
83
+ time.sleep(0.3)
81
84
  except: pass
82
85
 
83
86
  def _find_and_click_more(self) -> bool:
84
- return self._page.evaluate("""
87
+ result = self._page.evaluate("""
85
88
  (() => {
86
89
  const icons = document.querySelectorAll('svg[aria-label="More"]');
87
90
  for (const icon of icons) {
@@ -90,12 +93,15 @@ class BrowserDeleter:
90
93
  const r = icon.getBoundingClientRect();
91
94
  if (r.width < 5 || r.height < 5) continue;
92
95
  if (r.y < 100) continue;
93
- icon.dispatchEvent(new MouseEvent('click', {bubbles: true}));
94
- return true;
96
+ return {x: r.x + r.width / 2, y: r.y + r.height / 2};
95
97
  }
96
- return false;
98
+ return null;
97
99
  })()
98
100
  """)
101
+ if result is None:
102
+ return False
103
+ self._page.mouse.click(result["x"], result["y"])
104
+ return True
99
105
 
100
106
  def _click_menu_delete(self) -> bool:
101
107
  return self._page.evaluate("""
@@ -107,7 +113,7 @@ class BrowserDeleter:
107
113
  if (el.offsetParent === null) continue;
108
114
  const txt = el.innerText || el.textContent || '';
109
115
  if (txt.trim() === 'Delete') {
110
- el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
116
+ el.click();
111
117
  return true;
112
118
  }
113
119
  }
@@ -135,8 +141,9 @@ class BrowserDeleter:
135
141
  if (el.offsetParent === null) continue;
136
142
  const txt = el.innerText || el.textContent || '';
137
143
  if (txt.trim() === 'Delete') {
138
- if (el.closest('[role="dialog"], [role="alertdialog"]')) {
139
- el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
144
+ // Must NOT be inside the menu (which we already dismissed)
145
+ if (!el.closest('[role="menu"]')) {
146
+ el.click();
140
147
  return true;
141
148
  }
142
149
  }