mirror of
https://github.com/BoPeng/ai-marketplace-monitor.git
synced 2025-12-23 22:28:18 -05:00
* Make keyboard monitoring optional (#259) * release version 0.9.9
This commit is contained in:
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
None yet.
|
## [0.9.9]
|
||||||
|
|
||||||
|
- [Issue 259](https://github.com/BoPeng/ai-marketplace-monitor/pull/259). Disallow keyboard monitoring by default.
|
||||||
|
|
||||||
## [0.9.8]
|
## [0.9.8]
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ Features
|
|||||||
|
|
||||||
- **Search Statistics**: Track pages searched, listings examined, and matches found
|
- **Search Statistics**: Track pages searched, listings examined, and matches found
|
||||||
- **Performance Metrics**: Monitor search frequency and success rates
|
- **Performance Metrics**: Monitor search frequency and success rates
|
||||||
- **Interactive Mode**: Real-time statistics and manual listing checks
|
- **Interactive Mode**: Real-time statistics and manual listing checks (optional)
|
||||||
- **Persistent Counters**: Statistics maintained across program restarts
|
- **Persistent Counters**: Statistics maintained across program restarts
|
||||||
- **Individual Listing Analysis**: Debug why specific listings were included or excluded
|
- **Individual Listing Analysis**: Debug why specific listings were included or excluded
|
||||||
|
|
||||||
|
|||||||
@@ -223,10 +223,8 @@ Logs are typically saved to:
|
|||||||
|
|
||||||
**Interactive debugging**
|
**Interactive debugging**
|
||||||
|
|
||||||
While monitor is running:
|
- Use option ``--check URL`` when starting ai-marketplace-monitor to test individual listings
|
||||||
- Press ``Esc`` to view statistics
|
- Enter interactive mode by pressing any key while monitor is running. This feature requires the installation of `pynput` package.
|
||||||
- Use ``--check URL`` to test individual listings
|
|
||||||
- Enter interactive mode to debug specific issues
|
|
||||||
|
|
||||||
Getting Help
|
Getting Help
|
||||||
============
|
============
|
||||||
|
|||||||
@@ -74,6 +74,14 @@ While the monitor is running, you can:
|
|||||||
- Enter interactive mode to check individual URLs
|
- Enter interactive mode to check individual URLs
|
||||||
- Type ``exit`` to leave interactive mode
|
- Type ``exit`` to leave interactive mode
|
||||||
|
|
||||||
|
* This feature requires the installation of `pynput` package, which can be installed separately or through
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install 'ai-marketplace-monitor[pynput]'
|
||||||
|
```
|
||||||
|
|
||||||
|
You can disable this feature by define environment variable `DISABLE_PYNPUT=true` if `pynput` is already installed.
|
||||||
|
|
||||||
Cost Considerations
|
Cost Considerations
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
name = "ai-marketplace-monitor"
|
name = "ai-marketplace-monitor"
|
||||||
version = "0.9.8"
|
version = "0.9.9"
|
||||||
description = "An AI-based tool for monitoring facebook marketplace"
|
description = "An AI-based tool for monitoring facebook marketplace"
|
||||||
authors = [{ name = "Bo Peng", email = "ben.bob@gmail.com" }]
|
authors = [{ name = "Bo Peng", email = "ben.bob@gmail.com" }]
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@@ -28,7 +28,6 @@ dependencies = [
|
|||||||
"humanize>=4.0.0",
|
"humanize>=4.0.0",
|
||||||
"schedule>=1.2.2",
|
"schedule>=1.2.2",
|
||||||
"inflect>=7.0.0",
|
"inflect>=7.0.0",
|
||||||
"pynput>=1.7.0",
|
|
||||||
"pillow>=10.0.0",
|
"pillow>=10.0.0",
|
||||||
"jinja2>=3.0.0",
|
"jinja2>=3.0.0",
|
||||||
"pyparsing>=3.1.0",
|
"pyparsing>=3.1.0",
|
||||||
@@ -50,6 +49,7 @@ Documentation = "https://ai-marketplace-monitor.readthedocs.io"
|
|||||||
ai-marketplace-monitor = "ai_marketplace_monitor.cli:app"
|
ai-marketplace-monitor = "ai_marketplace_monitor.cli:app"
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
pynput = ["pynput>=1.7.0"]
|
||||||
dev = [
|
dev = [
|
||||||
"pre-commit>=4.0.1",
|
"pre-commit>=4.0.1",
|
||||||
"invoke>=2.2.0",
|
"invoke>=2.2.0",
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
__author__ = """Bo Peng"""
|
__author__ = """Bo Peng"""
|
||||||
__email__ = "ben.bob@gmail.com"
|
__email__ = "ben.bob@gmail.com"
|
||||||
__version__ = "0.9.8"
|
__version__ = "0.9.9"
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ from rich.pretty import pretty_repr
|
|||||||
try:
|
try:
|
||||||
from pynput import keyboard # type: ignore
|
from pynput import keyboard # type: ignore
|
||||||
|
|
||||||
pynput_installed = True
|
pynput_enabled = os.environ.get("DISABLE_PYNPUT", "").lower() not in ("1", "y", "true", "yes")
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# some platforms are not supported
|
# some platforms are not supported
|
||||||
pynput_installed = False
|
pynput_enabled = False
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ class KeyboardMonitor:
|
|||||||
self._confirmed: bool | None = None
|
self._confirmed: bool | None = None
|
||||||
|
|
||||||
def start(self: "KeyboardMonitor") -> None:
|
def start(self: "KeyboardMonitor") -> None:
|
||||||
if pynput_installed:
|
if pynput_enabled:
|
||||||
self._listener = keyboard.Listener(on_press=self.handle_key_press)
|
self._listener = keyboard.Listener(on_press=self.handle_key_press)
|
||||||
self._listener.start() # start to listen on a separate thread
|
self._listener.start() # start to listen on a separate thread
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class KeyboardMonitor:
|
|||||||
def set_paused(self: "KeyboardMonitor", paused: bool = True) -> None:
|
def set_paused(self: "KeyboardMonitor", paused: bool = True) -> None:
|
||||||
self._paused = paused
|
self._paused = paused
|
||||||
|
|
||||||
if pynput_installed:
|
if pynput_enabled:
|
||||||
|
|
||||||
def handle_key_press(
|
def handle_key_press(
|
||||||
self: "KeyboardMonitor", key: keyboard.Key | keyboard.KeyCode | None
|
self: "KeyboardMonitor", key: keyboard.Key | keyboard.KeyCode | None
|
||||||
|
|||||||
49
tasks.py
49
tasks.py
@@ -226,6 +226,55 @@ def release(c: Context, version: str) -> None:
|
|||||||
with open(file_path, "w") as f:
|
with open(file_path, "w") as f:
|
||||||
f.write("\n".join(lines))
|
f.write("\n".join(lines))
|
||||||
|
|
||||||
|
# Update CHANGELOG.md
|
||||||
|
print("Updating CHANGELOG.md...")
|
||||||
|
changelog_path = "CHANGELOG.md"
|
||||||
|
with open(changelog_path, "r") as f:
|
||||||
|
changelog_content = f.read()
|
||||||
|
|
||||||
|
# Find the [Unreleased] section
|
||||||
|
lines = changelog_content.split("\n")
|
||||||
|
updated_lines = []
|
||||||
|
i = 0
|
||||||
|
while i < len(lines):
|
||||||
|
if lines[i].strip() == "## [Unreleased]":
|
||||||
|
# Add the [Unreleased] header
|
||||||
|
updated_lines.append(lines[i])
|
||||||
|
|
||||||
|
# Collect all content under [Unreleased] until the next section
|
||||||
|
i += 1
|
||||||
|
unreleased_content = []
|
||||||
|
while i < len(lines) and not lines[i].startswith("## ["):
|
||||||
|
if lines[i].strip(): # Non-empty content line
|
||||||
|
unreleased_content.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# If there's content to move to the new version
|
||||||
|
if unreleased_content:
|
||||||
|
# Keep [Unreleased] section empty
|
||||||
|
updated_lines.append("")
|
||||||
|
|
||||||
|
# Add new version section with the content
|
||||||
|
updated_lines.append(f"## [{version}]")
|
||||||
|
updated_lines.append("")
|
||||||
|
updated_lines.extend(unreleased_content)
|
||||||
|
else:
|
||||||
|
# Just add empty line after [Unreleased]
|
||||||
|
updated_lines.append("")
|
||||||
|
|
||||||
|
# Continue with the rest of the file (next version sections)
|
||||||
|
if i < len(lines) and lines[i].startswith("## ["):
|
||||||
|
updated_lines.append("") # Add blank line before next section
|
||||||
|
updated_lines.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
updated_lines.append(lines[i])
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# Write back the updated changelog
|
||||||
|
with open(changelog_path, "w") as f:
|
||||||
|
f.write("\n".join(updated_lines))
|
||||||
|
|
||||||
# Clean previous builds
|
# Clean previous builds
|
||||||
print("Cleaning previous builds...")
|
print("Cleaning previous builds...")
|
||||||
_run(c, "rm -fr build/ dist/ *.egg-info")
|
_run(c, "rm -fr build/ dist/ *.egg-info")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from ai_marketplace_monitor.user import User
|
|||||||
|
|
||||||
def test_version(version: str) -> None:
|
def test_version(version: str) -> None:
|
||||||
"""Sample pytest test function with the pytest fixture as an argument."""
|
"""Sample pytest test function with the pytest fixture as an argument."""
|
||||||
assert version == "0.9.8"
|
assert version == "0.9.9"
|
||||||
|
|
||||||
|
|
||||||
def test_listing_cache(temp_cache: Cache, listing: Listing) -> None:
|
def test_listing_cache(temp_cache: Cache, listing: Listing) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user