mutimon 0.1.0__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.
mutimon/AI_GUIDE.md ADDED
@@ -0,0 +1,168 @@
1
+ # Mutimon — AI Guide for Adding Websites
2
+
3
+ You are configuring Mutimon, a config-driven web scraper. All config lives in `~/.mutimon/config.json`.
4
+ Your job: add a new website to monitor by editing that config file and creating a template.
5
+
6
+ ## What you need to do
7
+
8
+ 1. Fetch the target page HTML and inspect its structure
9
+ 2. Add a **definition** to `defs` (how to scrape)
10
+ 3. Add a **rule** to `rules` (when to scrape, who to email)
11
+ 4. Create a **Liquid template** file in `~/.mutimon/templates/`
12
+ 5. Validate: run `mon --validate`
13
+ 6. Test: run `mon --dry-run --force <rule_name>` to verify extraction works
14
+
15
+ ## Definition structure (`defs`)
16
+
17
+ ```json
18
+ "my-site": {
19
+ "url": "https://example.com/page",
20
+ "query": {
21
+ "type": "list",
22
+ "selector": "CSS selector for each item container",
23
+ "id": {
24
+ "type": "attribute",
25
+ "name": "data-id"
26
+ },
27
+ "variables": {
28
+ "title": {
29
+ "selector": "h3.title",
30
+ "value": { "type": "text" }
31
+ },
32
+ "url": {
33
+ "selector": "a",
34
+ "value": { "type": "attribute", "name": "href", "prefix": "https://example.com" }
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Key fields
42
+
43
+ - `url` — page URL, supports `{{param}}` Liquid variables for parametrized URLs
44
+ - `format` — `"html"` (default) or `"xml"` for RSS/Atom feeds
45
+ - `userAgent` — custom User-Agent string (some feeds/APIs block default agents)
46
+ - `query.type` — `"list"` (multiple items) or `"single"` (one value per page)
47
+ - `query.selector` — CSS selector for item containers
48
+ - `query.id` — how to get a unique ID: `{"type": "attribute", "name": "..."}` or `{"source": "url", "regex": "..."}`
49
+ - `query.expect` — array of CSS selectors that must exist (error email if missing, catches page redesigns)
50
+ - `query.reject` — array of CSS selectors that mean "no real results" (returns 0 items if any match)
51
+
52
+ ### Variable extraction
53
+
54
+ Each variable needs a `selector` and `value`:
55
+
56
+ ```json
57
+ "varname": {
58
+ "selector": "CSS selector relative to item container",
59
+ "value": { "type": "text" }
60
+ }
61
+ ```
62
+
63
+ Value types:
64
+ - `{"type": "text"}` — text content of the element
65
+ - `{"type": "attribute", "name": "href"}` — attribute value
66
+
67
+ Options:
68
+ - `"prefix": "https://..."` — prepend to the value (for relative URLs)
69
+ - `"regex": "(\\d+)"` — extract a capture group from the value
70
+ - `"parse": "number"` — parse as float (for numeric comparisons in validators)
71
+ - `"parse": "money"` — locale-aware currency parsing (strips currency symbols)
72
+ - `"default": ""` — fallback when element not found (prevents errors)
73
+ - `"collect": true` — extract ALL matching elements as a list (e.g. tags, skills)
74
+ - `"selector": ":self"` — reference the container element itself
75
+ - `"sibling": true` — search in the next sibling element (e.g. Hacker News score is in a different `<tr>`)
76
+
77
+ ## Rule structure (`rules`)
78
+
79
+ ```json
80
+ {
81
+ "ref": "my-site",
82
+ "name": "my-site-monitor",
83
+ "schedule": "0 */6 * * *",
84
+ "subject": "[my-site] {{count}} new item(s)",
85
+ "template": "./templates/my-site",
86
+ "email": "user@example.com"
87
+ }
88
+ ```
89
+
90
+ - `ref` — name of the definition in `defs`
91
+ - `name` — unique name, used as state filename
92
+ - `schedule` — cron expression (e.g. `"0 8 * * *"` = daily 8am, `"0 */4 * * *"` = every 4h)
93
+ - `subject` — Liquid template for email subject (`{{count}}` = number of new items)
94
+ - `template` — path to template file relative to `~/.mutimon/`
95
+ - `email` — recipient email address
96
+ - `params` — values for URL template variables (e.g. `{"query": "python"}`)
97
+
98
+ ## Template file
99
+
100
+ Create a plain text file in `~/.mutimon/templates/`. Example:
101
+
102
+ ```
103
+ New items from My Site
104
+ Checked at: {{ now }}
105
+
106
+ Found {{ count }} new item(s)
107
+ ============================================================
108
+ {% for item in items %}
109
+
110
+ {{ item.index }}. {{ item.title }}
111
+ URL: {{ item.url }}
112
+ {% endfor %}
113
+
114
+ ============================================================
115
+ ```
116
+
117
+ Available variables: `{{ count }}`, `{{ now }}`, `{{ search_url }}`, and all extracted variables via `{{ item.varname }}`.
118
+ For list variables (from `collect: true`): `{% for tag in item.tags %}{{ tag }}{% unless forloop.last %}, {% endunless %}{% endfor %}`
119
+
120
+ ## Complete example: Hacker News
121
+
122
+ Definition:
123
+ ```json
124
+ "hackernews": {
125
+ "url": "https://news.ycombinator.com",
126
+ "query": {
127
+ "type": "list",
128
+ "selector": "tr.athing.submission",
129
+ "id": { "type": "attribute", "name": "id" },
130
+ "variables": {
131
+ "title": {
132
+ "selector": ".titleline > a",
133
+ "value": { "type": "text" }
134
+ },
135
+ "url": {
136
+ "selector": ".titleline > a",
137
+ "value": { "type": "attribute", "name": "href" }
138
+ },
139
+ "score": {
140
+ "sibling": true,
141
+ "selector": ".score",
142
+ "value": { "type": "text", "regex": "(\\d+)", "parse": "number" },
143
+ "default": "0"
144
+ }
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Rule:
151
+ ```json
152
+ {
153
+ "ref": "hackernews",
154
+ "name": "hackernews",
155
+ "schedule": "0 */6 * * *",
156
+ "subject": "Hacker News: {{count}} new stories",
157
+ "template": "./templates/hackernews",
158
+ "email": "user@example.com"
159
+ }
160
+ ```
161
+
162
+ ## Tips
163
+
164
+ - Always add `"expect"` selectors to detect page redesigns
165
+ - Use `"default": ""` on optional variables to prevent extraction errors
166
+ - Use `mon --dry-run --force <name>` to test without sending emails or saving state
167
+ - For RSS/Atom feeds: use `"format": "xml"` and element names as selectors (e.g. `"item"`, `"entry"`)
168
+ - The `id` field is crucial — it's how Mutimon tracks which items are new
mutimon/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Mutimon — config-driven web scraper and email notifier."""
2
+
3
+ __version__ = "0.1.0"