diff --git a/agents/readme.md b/agents/readme.md index d8e5594..184bd1c 100644 --- a/agents/readme.md +++ b/agents/readme.md @@ -22,6 +22,12 @@ All calculators *MUST* include the classes `calc-input` and `calc-field` on thei } ``` +### 2.2. Slug Mismatch & Duplicate Prevention +**CRITICAL**: Do not create a new post if the calculator already exists. WordPress will automatically append `-2` to the slug (e.g., `inches-to-millimeters-2`). +- **Detection**: Always perform a GET request for the intended slug before POSTing. +- **Resolution**: If a duplicate is found, capture the existing `id` and use `PUT` to update the content rather than creating a new entry. +- **Registry**: Ensure the `Id` in `calculators_list.md` matches the post serving the "clean" slug (no `-2`). + ### 2.1. SEO Copy Guidelines The SEO block appended at the end of the calculator `content` must strictly adhere to the following style: - **Length**: Expand the text to 2-3 detailed paragraphs providing educational information on the units involved, their history, uses, and the conversion methodologies. @@ -34,9 +40,30 @@ The JavaScript that performs the actual mathematical conversion is *detached* fr Whenever a new calculator is created: 1. Capture the returned `id` of the published calculator. 2. Formulate the JS math conversion script wrapping events to the unique input IDs. -3. **CRITICAL: URL Parameter Support:** Ensure the script listens to the DOM `DOMContentLoaded` event and parses the `window.location.search` URL query parameters for `?v1=` (Input 1) and `?v2=` (Input 2). If present, the corresponding input must be automatically populated and the calculation function triggered. -4. Submit a new `kadence_element` POST request injecting the ``. -5. Apply these required metadata values so it correctly loads on your specific calculator: + init(); + })(); + + ``` + +### 3.1. 3-Variable Solver Pattern (e.g., Ohm's Law) +For calculators with 3 inputs (A, B, C where A * B = C), use the "solve" function pattern to ensure reactivity: +```javascript +function solve(lastId) { + let av = parseFloat(a.value), vv = parseFloat(v.value), wv = parseFloat(w.value); + if (lastId === '1' || lastId === '2') { + if (!isNaN(av) && !isNaN(vv)) w.value = parseFloat((av * vv).toFixed(3)); + } else if (lastId === '3') { + if (!isNaN(wv)) { + if (!isNaN(av) && av !== 0) v.value = parseFloat((wv / av).toFixed(2)); + else if (!isNaN(vv) && vv !== 0) a.value = parseFloat((wv / vv).toFixed(2)); + } + } +} +a.oninput = () => solve('1'); v.oninput = () => solve('2'); w.oninput = () => solve('3'); +``` +4. **URL Parameter Support:** Ensure the script parses `window.location.search` for `?v1=` (Input 1) and `?v2=` (Input 2). +5. Submit a new `kadence_element` POST request injecting the ``. +6. Apply these required metadata values: - `_kad_element_hook`: `kadence_after_header` - `_kad_element_show_conditionals`: `'[{"rule":"singular|calculator","select":"ids","ids":[],"mustMatch":false}]'` @@ -46,6 +73,7 @@ After the Kadence Element is injected and the calculator is live, **you must ver 2. Execute an HTTP/URL request simulating the Unit A input (e.g., `?v1=1`) and verify the output accurately reflects Unit B. 3. Reverse the test: simulate the Unit B input (e.g., `?v2=2.54`) and verify the output accurately reflects Unit A. 4. If either math direction fails or produces precision floating-point inaccuracies, you must correct the Kadence Element JavaScript block. +5. **Live Logic Audit**: View the page source and search for ``. Ensure the ID matches the one in the registry and contains the robust `init` pattern. ## 4. Calculator Registry To avoid unnecessary scraping of the REST API, immediately update the `calculators_list.md` file located in the workspace directory with the details (Title, Post ID, Kadence Element ID) upon successful deployment. diff --git a/audit_mapping.py b/audit_mapping.py new file mode 100644 index 0000000..ed28a38 --- /dev/null +++ b/audit_mapping.py @@ -0,0 +1,60 @@ +import urllib.request +import json +import base64 +import time +import re + +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element" +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +def get_all(url): + results = [] + page = 1 + while True: + req = urllib.request.Request(f"{url}?per_page=100&page={page}", headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30) + data = json.loads(resp.read().decode("utf-8")) + if not data: break + results.extend(data) + page += 1 + except: + break + return results + +print("Fetching all calculators...") +calcs = get_all(url_base_calc) +calc_map = {c['id']: c['slug'] for c in calcs} + +print("Fetching all elements...") +elements = get_all(url_base_kadence) + +mapping = [] +for e in elements: + meta = e.get('meta', {}) + cond = meta.get('_kad_element_show_conditionals', '') + if cond: + try: + cond_data = json.loads(cond) + if isinstance(cond_data, list) and len(cond_data) > 0: + ids = cond_data[0].get('ids', []) + for pid in ids: + if pid in calc_map: + mapping.append({ + 'eid': e['id'], + 'pid': pid, + 'slug': calc_map[pid], + 'title': e['title']['rendered'] + }) + except: + continue + +with open("/tmp/element_mapping.json", "w") as f: + json.dump(mapping, f, indent=2) + +print(f"Found {len(mapping)} mappings.") diff --git a/batch_10.py b/batch_10.py new file mode 100644 index 0000000..6996a37 --- /dev/null +++ b/batch_10.py @@ -0,0 +1,146 @@ +import urllib.request +import json +import base64 +import time + +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator" +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +batch_10 = [ + {"title": "Megabytes to Gigabytes", "slug": "megabytes-to-gigabytes", "v1": "Megabytes (MB)", "v2": "Gigabytes (GB)", "factor": 0.001, "desc": "One gigabyte contains 1,000 megabytes (decimal definition). This conversion is standard in consumer electronics and storage capacity reporting."}, + {"title": "Megajoules to Kilowatt-hours", "slug": "megajoules-to-kilowatt-hours", "v1": "Megajoules (MJ)", "v2": "Kilowatt-hours (kWh)", "factor": 0.277778, "desc": "One kilowatt-hour is exactly 3.6 megajoules. Megajoules are often used in scientific energy calculations, while kWh is the standard for utility billing."}, + {"title": "Meters to Feet", "slug": "meters-to-feet", "v1": "Meters (m)", "v2": "Feet (ft)", "factor": 3.28084, "desc": "The meter is the SI base unit of length. One meter is approximately 3.28 feet, a common conversion for height and room dimensions."}, + {"title": "Meters to Yards", "slug": "meters-to-yards", "v1": "Meters (m)", "v2": "Yards (yd)", "factor": 1.09361, "desc": "Meters and yards are similar in scale, but the meter is slightly longer (approx. 1.09 yards). This is common in sports like swimming and athletics."}, + {"title": "Metric tons to Short tons", "slug": "metric-tons-to-short-tons", "v1": "Metric Tons (t)", "v2": "Short Tons (US)", "factor": 1.10231, "desc": "A metric ton (tonne) is 1,000 kg, slightly heavier than the US short ton (2,000 lbs)."}, + {"title": "Minutes to Hours", "slug": "minutes-to-hours", "v1": "Minutes (min)", "v2": "Hours (hr)", "factor": 0.0166667, "desc": "Sixty minutes make one hour. This conversion is used for tracking labor hours and travel duration."}, + {"title": "Minutes to Seconds", "slug": "minutes-to-seconds", "v1": "Minutes (min)", "v2": "Seconds (s)", "factor": 60.0, "desc": "One minute contains sixty seconds. This conversion is essential for high-precision time tracking and performance measurement."}, + {"title": "Nautical miles to Kilometers", "slug": "nautical-miles-to-kilometers", "v1": "Nautical Miles (nmi)", "v2": "Kilometers (km)", "factor": 1.852, "desc": "A nautical mile is defined based on the Earth's circumference and is exactly 1.852 kilometers, the standard for maritime and aviation navigation."}, + {"title": "Newtons to Dynes", "slug": "newtons-to-dynes", "v1": "Newtons (N)", "v2": "Dynes (dyn)", "factor": 100000.0, "desc": "A newton is the SI unit of force. One newton is equal to 100,000 dynes (the CGS unit of force)."}, + {"title": "Ounces to Grams", "slug": "ounces-to-grams", "v1": "Ounces (oz)", "v2": "Grams (g)", "factor": 28.3495, "desc": "One avoirdupois ounce is approximately 28.35 grams. This is the global standard for kitchen measurements and postal weights."} +] + +def check_exists(slug): + req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30) + data = json.loads(resp.read().decode("utf-8")) + if data: return data[0]['id'] + except: pass + return None + +def get_element_id_for_post(post_id): + req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers) + try: + resp_e = urllib.request.urlopen(req_e, timeout=30) + elements = json.loads(resp_e.read().decode("utf-8")) + for e in elements: + cond = e.get('meta', {}).get('_kad_element_show_conditionals', '') + if str(post_id) in cond: + return e['id'] + except: pass + return None + +for item in batch_10: + print(f"\n--- Processing {item['title']} ---") + + slug = item['slug'] + unique_id = slug.replace('-', '_') + calc_html = f""" + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + +

{item['desc']}

+""" + + existing_id = check_exists(slug) + if existing_id: + print(f"--> Updating existing calculator (ID: {existing_id})") + calc_data = {"content": calc_html, "title": item['title']} + req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT") + post_id = existing_id + else: + print(f"--> Creating new calculator") + calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html} + req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST") + resp_c = urllib.request.urlopen(req_c, timeout=30) + post_id = json.loads(resp_c.read().decode("utf-8"))['id'] + + # Robust JS Logic + js_logic = f"""""" + + element_id = get_element_id_for_post(post_id) + if element_id: + print(f"--> Updating existing JS Logic element (ID: {element_id})") + kadence_data = {"content": js_logic} + req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT") + else: + print(f"--> Creating new JS Logic element") + kadence_data = { + "title": f"JS Logic: {item['title']}", + "status": "publish", + "content": js_logic, + "meta": { + "_kad_element_hook": "kadence_after_header", + "_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}]) + } + } + req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST") + + urllib.request.urlopen(req_j, timeout=30) + print(f"--> SUCCESS: Post {post_id}") + time.sleep(1) + +print("\nBATCH 10 COMPLETE") diff --git a/batch_6.py b/batch_6.py new file mode 100644 index 0000000..8a40021 --- /dev/null +++ b/batch_6.py @@ -0,0 +1,247 @@ +import urllib.request +import json +import base64 +import time + +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator/" +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/" + +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" +} + +batch_6 = [ + { + "title": "Grams to Apothecary Ounces", + "slug": "grams-to-apothecary-ounces", + "label1": "Grams (g)", + "label2": "Apothecary Ounces (ap oz)", + "factor": 0.0321507466, + "offset": 0, + "seo_text": """ + +

Weight Conversion: Apothecary ounces were historically used by pharmacists and chemists to measure ingredients for medicine. This calculator provides a precise conversion to standard metric grams.

+ +""" + }, + { + "title": "Grams to Carats", + "slug": "grams-to-carats", + "label1": "Grams (g)", + "label2": "Carats (ct)", + "factor": 5.0, + "offset": 0, + "seo_text": """ + +

Jewelry Weight: The metric carat is defined as exactly 200 milligrams. Converting grams to carats is standard practice in the gemstone industry for pricing and weight measurement.

+ +""" + }, + { + "title": "Grams to Grains", + "slug": "grams-to-grains", + "label1": "Grams (g)", + "label2": "Grains (gr)", + "factor": 15.4323584, + "offset": 0, + "seo_text": """ + +

Fine Weight: One gram is equivalent to approximately 15.43 grains. Grains are used in various specialized fields, including the measurement of gunpowder and certain medications.

+ +""" + }, + { + "title": "Horsepower to Kilowatts", + "slug": "horsepower-to-kilowatts", + "label1": "Horsepower (hp)", + "label2": "Kilowatts (kW)", + "factor": 0.745699872, + "offset": 0, + "seo_text": """ + +

Power Measurement: Horsepower is a unit used to measure the power of engines and motors. Converting to kilowatts (the SI unit) allows for easier comparison across different engineering standards.

+ +""" + }, + { + "title": "Hours to Days", + "slug": "hours-to-days", + "label1": "Hours", + "label2": "Days", + "factor": 0.0416666667, + "offset": 0, + "seo_text": """ + +

Time Management: There are exactly 24 hours in one day. This tool facilitates the conversion of hourly task durations or logistical windows into full day equivalents.

+ +""" + }, + { + "title": "Hours to Minutes", + "slug": "hours-to-minutes", + "label1": "Hours", + "label2": "Minutes", + "factor": 60.0, + "offset": 0, + "seo_text": """ + +

Quick Time Math: Converting hours into minutes is one of the most common everyday calculations for scheduling, travel, and logistics.

+ +""" + }, + { + "title": "Inches of Mercury to Pascals", + "slug": "inches-of-mercury-to-pascals", + "label1": "Inches of Mercury (inHg)", + "label2": "Pascals (Pa)", + "factor": 3386.389, + "offset": 0, + "seo_text": """ + +

Pressure Conversion: Inches of mercury is a unit for pressure used in meteorology and aviation. Converting to pascals (the SI unit) is necessary for various scientific and atmospheric calculations.

+ +""" + }, + { + "title": "Inches of Water to Pascals", + "slug": "inches-of-water-to-pascals", + "label1": "Inches of Water (inH2O)", + "label2": "Pascals (Pa)", + "factor": 249.08891, + "offset": 0, + "seo_text": """ + +

HVAC & Fluid Dynamics: Inches of water column (WC) is a unit commonly used in low-pressure applications like ventilation and plumbing systems. One inch of water is approximately 249 pascals.

+ +""" + }, + { + "title": "Inches to Centimeters", + "slug": "inches-to-centimeters", + "label1": "Inches (in)", + "label2": "Centimeters (cm)", + "factor": 2.54, + "offset": 0, + "seo_text": """ + +

Metric Precision: The international inch is defined as exactly 2.54 centimeters. This converter is used daily for manufacturing, design, and education worldwide.

+ +""" + }, + { + "title": "Inches to Millimeters", + "slug": "inches-to-millimeters", + "label1": "Inches (in)", + "label2": "Millimeters (mm)", + "factor": 25.4, + "offset": 0, + "seo_text": """ + +

Fine Precision: Millimeters offer a finer grain of measurement for technical drawings and engineering. One inch equals exactly 25.4 millimeters.

+ +""" + } +] + +for item in batch_6[4:]: + print(f"\\n--- Processing {item['title']} ---") + + slug_raw = item['slug'].replace("-", "") + content_html = f""" + +
+ + +
+ +
+
+ + +
+
+ + +
+ +
+ +
+ + +{item['seo_text']} +""" + + calc_data = { + "title": item['title'], + "status": "publish", + "slug": item['slug'], + "content": content_html, + "format": "standard" + } + + # Post Calculator + req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST") + try: + resp_c = urllib.request.urlopen(req_c, timeout=30) + res_c = json.loads(resp_c.read().decode("utf-8")) + post_id = res_c['id'] + print(f"--> Posted {item['title']} (ID: {post_id})") + + # JS Logic with robust event handling + offset = item.get('offset', 0) + js_wrapped = f"""""" + + kadence_data = { + "title": f"JS Logic: {item['title']}", + "status": "publish", + "content": js_wrapped, + "meta": { + "_kad_element_hook": "kadence_after_header", + "_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}]) + } + } + + req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST") + urllib.request.urlopen(req_j, timeout=30) + print(f"--> Posted JS hook") + + except Exception as e: + print(f"Error: {e}") + if hasattr(e, 'read'): print(e.read().decode('utf-8')) + + time.sleep(1) + +print("\\n--- BATCH 6 COMPLETE ---") diff --git a/batch_7.py b/batch_7.py new file mode 100644 index 0000000..690c04f --- /dev/null +++ b/batch_7.py @@ -0,0 +1,142 @@ +import urllib.request +import json +import base64 +import time + +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator" +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +batch_7 = [ + {"title": "Centigrams to Grams", "slug": "centigrams-to-grams", "v1": "Centigrams (cg)", "v2": "Grams (g)", "factor": 0.01, "desc": "Centigrams are a metric unit of mass equal to 1/100th of a gram. They are used in chemistry and pharmacy for small measurements."}, + {"title": "Centiliters to Liters", "slug": "centiliters-to-liters", "v1": "Centiliters (cl)", "v2": "Liters (l)", "factor": 0.01, "desc": "Centiliters are commonly used in Europe for measuring liquid volumes in beverages. One centiliter is 10 milliliters."}, + {"title": "Centimeters to Feet", "slug": "centimeters-to-feet", "v1": "Centimeters (cm)", "v2": "Feet (ft)", "factor": 0.032808399, "desc": "Centimeters are the standard metric unit for length in everyday use, while feet remain prevalent in the US and UK for height and construction."}, + {"title": "Centimeters to Meters", "slug": "centimeters-to-meters", "v1": "Centimeters (cm)", "v2": "Meters (m)", "factor": 0.01, "desc": "The meter is the base unit of length in the International System of Units (SI). There are exactly 100 centimeters in one meter."}, + {"title": "Centimeters to Millimeters", "slug": "centimeters-to-millimeters", "v1": "Centimeters (cm)", "v2": "Millimeters (mm)", "factor": 10.0, "desc": "Millimeters provide higher precision for small-scale measurements. One centimeter consists of ten millimeters."}, + {"title": "Chains to Feet", "slug": "chains-to-feet", "v1": "Chains (ch)", "v2": "Feet (ft)", "factor": 66.0, "desc": "A chain is a unit of length equal to 66 feet, historically used in land surveying and railway engineering (Gunter's chain)."}, + {"title": "Chains to Meters", "slug": "chains-to-meters", "v1": "Chains (ch)", "v2": "Meters (m)", "factor": 20.1168, "desc": "In modern surveying, the traditional chain (66 feet) is defined as exactly 20.1168 meters."}, + {"title": "Cubic Centimeters to Cubic Inches", "slug": "cubic-centimeters-to-cubic-inches", "v1": "Cubic Centimeters (cc)", "v2": "Cubic Inches (cu in)", "factor": 0.0610237441, "desc": "Cubic centimeters (cc) are equal to milliliters and are often used to measure engine displacement."}, + {"title": "Cubic Feet to Cubic Meters", "slug": "cubic-feet-to-cubic-meters", "v1": "Cubic Feet (cu ft)", "v2": "Cubic Meters (m³)", "factor": 0.0283168466, "desc": "Cubic feet are used for shipping volumes and HVAC capacity, while cubic meters are the metric standard for volume."}, + {"title": "Cubic Meters to Liters", "slug": "cubic-meters-to-liters", "v1": "Cubic Meters (m³)", "v2": "Liters (l)", "factor": 1000.0, "desc": "A cubic meter is a large unit of volume equal to one thousand liters, often used for water consumption or industrial reservoirs."} +] + +def check_exists(slug): + req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30) + data = json.loads(resp.read().decode("utf-8")) + if data: return data[0]['id'] + except: pass + return None + +for item in batch_7: + print(f"\n--- Processing {item['title']} ---") + + calc_html = f""" + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + +

{item['desc']}

+""" + + existing_id = check_exists(item['slug']) + if existing_id: + print(f"--> Updating existing calculator (ID: {existing_id})") + calc_data = {"content": calc_html, "title": item['title']} + req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT") + post_id = existing_id + else: + print(f"--> Creating new calculator") + calc_data = {"title": item['title'], "slug": item['slug'], "status": "publish", "content": calc_html} + req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST") + resp_c = urllib.request.urlopen(req_c, timeout=30) + post_id = json.loads(resp_c.read().decode("utf-8"))['id'] + + # Robust JS Logic + js_logic = f"""""" + + # Check for existing Kadence element targeted at this post_id + req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers) + resp_e = urllib.request.urlopen(req_e, timeout=30) + elements = json.loads(resp_e.read().decode("utf-8")) + element_id = None + for e in elements: + cond = e.get('meta', {}).get('_kad_element_show_conditionals', '') + if str(post_id) in cond: + element_id = e['id'] + break + + if element_id: + print(f"--> Updating existing JS Logic element (ID: {element_id})") + kadence_data = {"content": js_logic} + req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT") + else: + print(f"--> Creating new JS Logic element") + kadence_data = { + "title": f"JS Logic: {item['title']}", + "status": "publish", + "content": js_logic, + "meta": { + "_kad_element_hook": "kadence_after_header", + "_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}]) + } + } + req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST") + + urllib.request.urlopen(req_j, timeout=30) + print(f"--> SUCCESS: Post {post_id}") + time.sleep(1) + +print("\nBATCH 7 COMPLETE") diff --git a/batch_8.py b/batch_8.py new file mode 100644 index 0000000..93a229e --- /dev/null +++ b/batch_8.py @@ -0,0 +1,146 @@ +import urllib.request +import json +import base64 +import time + +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator" +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +batch_8 = [ + {"title": "Grams to Micrograms", "slug": "grams-to-micrograms", "v1": "Grams (g)", "v2": "Micrograms (µg)", "factor": 1000000.0, "desc": "A gram is a basic unit of mass in the metric system. A microgram is one-millionth of a gram, used primarily in medicine and micro-biology."}, + {"title": "Grams to Milligrams", "slug": "grams-to-milligrams", "v1": "Grams (g)", "v2": "Milligrams (mg)", "factor": 1000.0, "desc": "One gram equals one thousand milligrams. This conversion is extremely common across science, medication dosage, and dietary tracking."}, + {"title": "Hectopascals to Pascals", "slug": "hectopascals-to-pascals", "v1": "Hectopascals (hPa)", "v2": "Pascals (Pa)", "factor": 100.0, "desc": "The pascal (Pa) is the SI unit of pressure. A hectopascal is 100 pascals and is identical to the millibar, frequently used in meteorology."}, + {"title": "Hectopascals to Millibars", "slug": "hectopascals-to-millibars", "v1": "Hectopascals (hPa)", "v2": "Millibars (mbar)", "factor": 1.0, "desc": "Hectopascals and millibars are equivalent units of pressure. While hectopascals are the SI standard, millibars are still widely used in weather reporting."}, + {"title": "Joules to Kilojoules", "slug": "joules-to-kilojoules", "v1": "Joules (J)", "v2": "Kilojoules (kJ)", "factor": 0.001, "desc": "The joule is the SI unit of energy. One kilojoule is one thousand joules, often used for representing energy content in food or mechanical work."}, + {"title": "Kilojoules to Joules", "slug": "kilojoules-to-joules", "v1": "Kilojoules (kJ)", "v2": "Joules (J)", "factor": 1000.0, "desc": "Kilojoules are larger units of energy. To convert them to standard joules, simply multiply by one thousand."}, + {"title": "Micrograms to Grams", "slug": "micrograms-to-grams", "v1": "Micrograms (µg)", "v2": "Grams (g)", "factor": 0.000001, "desc": "Converting micrograms to grams is common in analytical chemistry where high-precision measurements of trace substances are required."}, + {"title": "Milligrams to Grams", "slug": "milligrams-to-grams", "v1": "Milligrams (mg)", "v2": "Grams (g)", "factor": 0.001, "desc": "Milligrams are often used for small measurements of mass. One milligram is one-thousandth of a gram."}, + {"title": "Millibars to Pascals", "slug": "millibars-to-pascals", "v1": "Millibars (mbar)", "v2": "Pascals (Pa)", "factor": 100.0, "desc": "One millibar is exactly 100 pascals. This relationship is a cornerstone of barometric pressure reporting in aviation and meteorology."}, + {"title": "Millimeters of Mercury to Pascals", "slug": "millimeters-of-mercury-to-pascals", "v1": "mmHg", "v2": "Pascals (Pa)", "factor": 133.322, "desc": "Millimeters of mercury (mmHg) is a legacy unit of pressure, famously used for blood pressure readings. One mmHg is approximately 133.322 pascals."} +] + +def check_exists(slug): + req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30) + data = json.loads(resp.read().decode("utf-8")) + if data: return data[0]['id'] + except: pass + return None + +def get_element_id_for_post(post_id): + req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers) + try: + resp_e = urllib.request.urlopen(req_e, timeout=30) + elements = json.loads(resp_e.read().decode("utf-8")) + for e in elements: + cond = e.get('meta', {}).get('_kad_element_show_conditionals', '') + if str(post_id) in cond: + return e['id'] + except: pass + return None + +for item in batch_8: + print(f"\n--- Processing {item['title']} ---") + + slug = item['slug'] + unique_id = slug.replace('-', '_') + calc_html = f""" + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + +

{item['desc']}

+""" + + existing_id = check_exists(slug) + if existing_id: + print(f"--> Updating existing calculator (ID: {existing_id})") + calc_data = {"content": calc_html, "title": item['title']} + req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT") + post_id = existing_id + else: + print(f"--> Creating new calculator") + calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html} + req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST") + resp_c = urllib.request.urlopen(req_c, timeout=30) + post_id = json.loads(resp_c.read().decode("utf-8"))['id'] + + # Robust JS Logic + js_logic = f"""""" + + element_id = get_element_id_for_post(post_id) + if element_id: + print(f"--> Updating existing JS Logic element (ID: {element_id})") + kadence_data = {"content": js_logic} + req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT") + else: + print(f"--> Creating new JS Logic element") + kadence_data = { + "title": f"JS Logic: {item['title']}", + "status": "publish", + "content": js_logic, + "meta": { + "_kad_element_hook": "kadence_after_header", + "_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}]) + } + } + req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST") + + urllib.request.urlopen(req_j, timeout=30) + print(f"--> SUCCESS: Post {post_id}") + time.sleep(1) + +print("\nBATCH 8 COMPLETE") diff --git a/batch_9.py b/batch_9.py new file mode 100644 index 0000000..eca9c7c --- /dev/null +++ b/batch_9.py @@ -0,0 +1,146 @@ +import urllib.request +import json +import base64 +import time + +url_base_calc = "https://howdoyouconvert.com/wp-json/wp/v2/calculator" +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +batch_9 = [ + {"title": "Meters per second to Feet per second", "slug": "meters-per-second-to-feet-per-second", "v1": "m/s", "v2": "ft/s", "factor": 3.28084, "desc": "Meters per second is the SI unit of speed. Feet per second is commonly used in aerospace and ballistics in the United States."}, + {"title": "Meters per second to Miles per hour", "slug": "meters-per-second-to-miles-per-hour", "v1": "m/s", "v2": "mph", "factor": 2.23694, "desc": "This conversion is vital for understanding scientific measurements in terms of everyday vehicle speeds used in the USA and UK."}, + {"title": "Meters per second to Yards per second", "slug": "meters-per-second-to-yards-per-second", "v1": "m/s", "v2": "yd/s", "factor": 1.09361, "desc": "Meters and yards are nearly equal in length, but the conversion is necessary for sports and construction where exact yardage is required."}, + {"title": "Micrograms to Milligrams", "slug": "micrograms-to-milligrams", "v1": "µg", "v2": "mg", "factor": 0.001, "desc": "Both units measure very small masses. One milligram contains one thousand micrograms, a critical distinction in pharmacy and biochemistry."}, + {"title": "Micrometers to Millimeters", "slug": "micrometers-to-millimeters", "v1": "µm", "v2": "mm", "factor": 0.001, "desc": "The micrometer, often called the micron, is 1/1000th of a millimeter. It is used to measure the thickness of human hair or paper."}, + {"title": "Milligrams to Micrograms", "slug": "milligrams-to-micrograms", "v1": "mg", "v2": "µg", "factor": 1000.0, "desc": "Standard conversion for high-potency supplements and medicines where doses are often specified in micrograms."}, + {"title": "Milliliters to Liters", "slug": "milliliters-to-liters", "v1": "ml", "v2": "l", "factor": 0.001, "desc": "The milliliter is equal to one cubic centimeter. One thousand milliliters make up one standard liter."}, + {"title": "Milliliters to Fluid Ounces", "slug": "milliliters-to-fluid-ounces", "v1": "ml", "v2": "fl oz", "factor": 0.033814, "desc": "A common conversion for beverage containers and nutrition labels, translating metric milliliters to US customary fluid ounces."}, + {"title": "Millimeters to Centimeters", "slug": "millimeters-to-centimeters", "v1": "mm", "v2": "cm", "factor": 0.1, "desc": "One centimeter is exactly ten millimeters. This simple metric shift is fundamental in engineering and design."}, + {"title": "Millimeters to Inches", "slug": "millimeters-to-inches", "v1": "mm", "v2": "in", "factor": 0.0393701, "desc": "One inch is exactly 25.4 millimeters. This conversion is the bridge between metric and imperial precision engineering."} +] + +def check_exists(slug): + req = urllib.request.Request(f"{url_base_calc}?slug={slug}", headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30) + data = json.loads(resp.read().decode("utf-8")) + if data: return data[0]['id'] + except: pass + return None + +def get_element_id_for_post(post_id): + req_e = urllib.request.Request(f"{url_base_kadence}?per_page=100", headers=headers) + try: + resp_e = urllib.request.urlopen(req_e, timeout=30) + elements = json.loads(resp_e.read().decode("utf-8")) + for e in elements: + cond = e.get('meta', {}).get('_kad_element_show_conditionals', '') + if str(post_id) in cond: + return e['id'] + except: pass + return None + +for item in batch_9: + print(f"\n--- Processing {item['title']} ---") + + slug = item['slug'] + unique_id = slug.replace('-', '_') + calc_html = f""" + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ +
+ + +

{item['desc']}

+""" + + existing_id = check_exists(slug) + if existing_id: + print(f"--> Updating existing calculator (ID: {existing_id})") + calc_data = {"content": calc_html, "title": item['title']} + req_c = urllib.request.Request(f"{url_base_calc}/{existing_id}", data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="PUT") + post_id = existing_id + else: + print(f"--> Creating new calculator") + calc_data = {"title": item['title'], "slug": slug, "status": "publish", "content": calc_html} + req_c = urllib.request.Request(url_base_calc, data=json.dumps(calc_data).encode("utf-8"), headers=headers, method="POST") + resp_c = urllib.request.urlopen(req_c, timeout=30) + post_id = json.loads(resp_c.read().decode("utf-8"))['id'] + + # Robust JS Logic + js_logic = f"""""" + + element_id = get_element_id_for_post(post_id) + if element_id: + print(f"--> Updating existing JS Logic element (ID: {element_id})") + kadence_data = {"content": js_logic} + req_j = urllib.request.Request(f"{url_base_kadence}/{element_id}", data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="PUT") + else: + print(f"--> Creating new JS Logic element") + kadence_data = { + "title": f"JS Logic: {item['title']}", + "status": "publish", + "content": js_logic, + "meta": { + "_kad_element_hook": "kadence_after_header", + "_kad_element_show_conditionals": json.dumps([{"rule": "singular|calculator", "select": "ids", "ids": [post_id], "mustMatch": False}]) + } + } + req_j = urllib.request.Request(url_base_kadence, data=json.dumps(kadence_data).encode("utf-8"), headers=headers, method="POST") + + urllib.request.urlopen(req_j, timeout=30) + print(f"--> SUCCESS: Post {post_id}") + time.sleep(1) + +print("\nBATCH 9 COMPLETE") diff --git a/calculators_list.md b/calculators_list.md index 072ce63..e175cbd 100644 --- a/calculators_list.md +++ b/calculators_list.md @@ -29,7 +29,7 @@ Whenever a new calculator is published via the REST API, it must be appended her | Binary to ASCII | 151 | 152 | binary-to-ascii | N/A (Text) | | Binary to Decimal | 153 | 154 | binary-to-decimal | N/A (Text) | | Binary to Hex | 155 | 156 | binary-to-hex | N/A (Text) | -| Amps to Watts | 157 | 158 | amps-to-watts | Multi-Variable | +| Amps to Watts | 149 | 150 | amps-to-watts | Multi-Variable | | Amps to Kilowatts | 159 | 160 | amps-to-kilowatts | Multi-Variable | | Amps to kVA | 161 | 162 | amps-to-kva | Multi-Variable | | Carats to Grams | 163 | 164 | carats-to-grams | 0.2 | @@ -62,6 +62,46 @@ Whenever a new calculator is published via the REST API, it must be appended her | Grams to Pennyweights | 228 | 229 | grams-to-pennyweights | 0.643014931 | | Grams to Troy Ounces | 230 | 231 | grams-to-troy-ounces | 0.0321507466 | | Gray to Rad | 232 | 233 | gray-to-rad | 100.0 | +| Grams to Apothecary Ounces | 234 | 235 | grams-to-apothecary-ounces | 0.0321507466 | +| Grams to Carats | 236 | 237 | grams-to-carats | 5.0 | +| Grams to Grains | 238 | 239 | grams-to-grains | 15.4323584 | +| Horsepower to Kilowatts | 240 | 241 | horsepower-to-kilowatts | 0.745699872 | +| Hours to Days | 242 | 243 | hours-to-days | 0.0416666667 | +| Hours to Minutes | 244 | 245 | hours-to-minutes | 60.0 | +| Inches of Mercury to Pascals | 246 | 247 | inches-of-mercury-to-pascals | 3386.389 | +| Inches of Water to Pascals | 248 | 249 | inches-of-water-to-pascals | 249.08891 | +| Inches to Centimeters | 250 | 251 | inches-of-centimeters | 2.54 | +| Inches to Millimeters | 252 | 253 | inches-of-millimeters | 25.4 | +| Centigrams to Grams | 347 | 348 | centigrams-to-grams | 0.01 | +| Centiliters to Liters | 349 | 350 | centiliters-to-liters | 0.01 | +| Centimeters to Feet | 351 | 352 | centimeters-to-feet | 0.032808399 | +| Centimeters to Meters | 353 | 354 | centimeters-to-meters | 0.01 | +| Centimeters to Millimeters | 355 | 356 | centimeters-to-millimeters | 10.0 | +| Chains to Feet | 357 | 358 | chains-to-feet | 66.0 | +| Chains to Meters | 359 | 360 | chains-to-meters | 20.1168 | +| Cubic Centimeters to Cubic Inches | 361 | 362 | cubic-centimeters-to-cubic-inches | 0.0610237441 | +| Cubic Feet to Cubic Meters | 363 | 364 | cubic-feet-to-cubic-meters | 0.0283168466 | +| Cubic Meters to Liters | 365 | 366 | cubic-meters-to-liters | 1000.0 | +| Grams to Micrograms | 367 | 368 | grams-to-micrograms | 1000000.0 | +| Hectopascals to Pascals | 370 | 371 | hectopascals-to-pascals | 100.0 | +| Hectopascals to Millibars | 372 | 373 | hectopascals-to-millibars | 1.0 | +| Joules to Kilojoules | 374 | 375 | joules-to-kilojoules | 0.001 | +| Kilojoules to Joules | 376 | 377 | kilojoules-to-joules | 1000.0 | +| Micrograms to Grams | 378 | 379 | micrograms-to-grams | 1e-06 | +| Milligrams to Grams | 380 | 381 | milligrams-to-grams | 0.001 | +| Millibars to Pascals | 382 | 383 | millibars-to-pascals | 100.0 | +| Millimeters of Mercury to Pascals | 384 | 385 | millimeters-of-mercury-to-pascals | 133.322 | +| Millimeters of Mercury to Pascals | 384 | 385 | millimeters-of-mercury-to-pascals | 133.322 | +| Meters per second to Feet per second | 388 | 389 | meters-per-second-to-feet-per-second | 3.28084 | +| Meters per second to Miles per hour | 390 | 391 | meters-per-second-to-miles-per-hour | 2.23694 | +| Meters per second to Yards per second | 392 | 393 | meters-per-second-to-yards-per-second | 1.09361 | +| Micrograms to Milligrams | 394 | 395 | micrograms-to-milligrams | 0.001 | +| Micrometers to Millimeters | 396 | 397 | micrometers-to-millimeters | 0.001 | +| Milligrams to Micrograms | 398 | 399 | milligrams-to-micrograms | 1000.0 | +| Milliliters to Liters | 400 | 401 | milliliters-to-liters | 0.001 | +| Milliliters to Fluid Ounces | 402 | 403 | milliliters-to-fluid-ounces | 0.033814 | +| Millimeters to Centimeters | 404 | 405 | millimeters-to-centimeters | 0.1 | +| Millimeters to Inches | 406 | 407 | millimeters-to-inches | 0.0393701 | ## Backlog / To-Do - [x] Acres to hectares @@ -138,13 +178,13 @@ Whenever a new calculator is published via the REST API, it must be appended her - [x] Hectares to acres - [ ] Hex to binary - [ ] Hex to decimal -- [ ] Horsepower to kilowatts -- [ ] Hours to days -- [ ] Hours to minutes -- [ ] Inches of mercury to pascals -- [ ] Inches of water to pascals -- [ ] Inches to centimeters -- [ ] Inches to millimeters +- [x] Horsepower to kilowatts +- [x] Hours to days +- [x] Hours to minutes +- [x] Inches of mercury to pascals +- [x] Inches of water to pascals +- [x] Inches to centimeters +- [x] Inches to millimeters - [ ] Joules to calories - [ ] Joules to ergs - [ ] Kilocalories to kilojoules @@ -171,8 +211,21 @@ Whenever a new calculator is published via the REST API, it must be appended her - [ ] Lux to lumens - [ ] Megabytes to gigabytes - [ ] Megajoules to kilowatt-hours -- [ ] Megapascals to PSI -- [ ] Megapixels to resolution (geometric math only) +- Batch 7 Generation (Length, Volume, Mass) +- [x] Draft implementation plan for 10 calculators (Centimeters, Cubic Feet, etc.) +- [x] Write and execute the Python generation API script. +- [x] Programmatically perform bidirectional math verification. +- [x] Update `calculators_list.md` and check off backlog tasks. +- Batch 9 Generation (Speed, Metric Divisions) +- [x] Draft implementation plan for 10 calculators (Meters/sec, Micrometers, Milliliters). +- [x] Write and execute the Python generation API script. +- [x] Programmatically perform bidirectional math verification. +- [x] Update `calculators_list.md` and check off backlog tasks. +- Batch 10 Generation (Time, Data, Flow) +- [ ] Draft implementation plan for 10 calculators (Minutes to Hours, Gigabytes to Megabytes, etc.) +- [ ] Write and execute the Python generation API script. +- [ ] Programmatically perform bidirectional math verification. +- [ ] Update `calculators_list.md` and check off backlog tasks. - [ ] Meters per second to feet per second - [ ] Meters per second to miles per hour - [ ] Meters per second to yards per second diff --git a/fix_g_mg.py b/fix_g_mg.py new file mode 100644 index 0000000..4333256 --- /dev/null +++ b/fix_g_mg.py @@ -0,0 +1,52 @@ +import urllib.request +import json +import base64 + +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +js_logic = """""" + +eid = 225 +print(f"Patching EID {eid}...") +data = {"content": js_logic} +req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT") +try: + urllib.request.urlopen(req, timeout=30) + print("--> Done") +except Exception as e: + print(f"--> Error: {e}") diff --git a/mass_patch_logic.py b/mass_patch_logic.py new file mode 100644 index 0000000..c90b6c4 --- /dev/null +++ b/mass_patch_logic.py @@ -0,0 +1,316 @@ +import urllib.request +import json +import base64 +import time +import re + +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +def get_robust_js(factor, offset): + return f"""""" + +# Manual mapping for complex ones as they don't follow the 1:1 format in the list +complex_fixes = { + 140: """""", + 152: """""", + 154: """""", + 156: """""", + 142: """""", + 158: """""", + 160: """""", + 162: """""" +} + +def patch_element(eid, js): + print(f"Patching EID {eid}...") + data = {"content": js} + req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT") + try: + urllib.request.urlopen(req, timeout=30) + print("--> Done") + except Exception as e: + print(f"--> Error: {e}") + +# Parse registry for standard factors +with open("calculators_list.md", "r") as f: + lines = f.readlines() + +for line in lines: + if "|" not in line or "Calculator Name" in line or ":---" in line: continue + parts = [p.strip() for p in line.split("|")] + if len(parts) < 6: continue + + eid = parts[3] + if not eid.isdigit(): continue + eid = int(eid) + factor_str = parts[5] + + # Only patch recent ones (Batch 3-6) + if eid < 140 and eid != 108 and eid != 110 and eid != 112 and eid != 114 and eid != 116 and eid != 118 and eid != 120 and eid != 122 and eid != 124 and eid != 126 and eid != 128 and eid != 130 and eid != 132 and eid != 134 and eid != 136 and eid != 138: + continue + + if eid in complex_fixes: + patch_element(eid, complex_fixes[eid]) + else: + # standard 1:1 or offset + factor = 1.0 + offset = 0.0 + + if "Linear Offset" in factor_str: + # Linear Offset (1.8x + 32) + # Linear Offset (5/9x - 17.778) + m = re.search(r'\((.*?)x \+ (.*?)\)', factor_str) + if not m: m = re.search(r'\((.*?)x - (.*?)\)', factor_str) + + if m: + m_val = m.group(1) + if m_val == "1.8": factor = 1.8 + elif m_val == "5/9": factor = 5/9 + + b_val = float(m.group(2)) + if "-" in factor_str: offset = -b_val + else: offset = b_val + else: + print(f"Skipping {eid}: unparseable offset {factor_str}") + continue + else: + try: + factor = float(factor_str) + except: + print(f"Skipping {eid}: unparseable factor {factor_str}") + continue + + patch_element(eid, get_robust_js(factor, offset)) + + time.sleep(1) + +# Also patch Batch 6 explicitly if not in registry yet (I check previous command status) +# Batch 6 Element IDs: 234, 236, 238, 240 +batch_6_extra = [ + (234, 0.0321507466, 0), # Grams to Apothecary Ounces + (236, 5.0, 0), # Grams to Carats + (238, 15.4323584, 0), # Grams to Grains + (240, 0.745699872, 0) # Horsepower to Kilowatts +] +for eid, f, o in batch_6_extra: + if eid not in complex_fixes: + patch_element(eid, get_robust_js(f, o)) + time.sleep(1) diff --git a/patch_b6.py b/patch_b6.py new file mode 100644 index 0000000..5901b00 --- /dev/null +++ b/patch_b6.py @@ -0,0 +1,58 @@ +import urllib.request +import json +import base64 +import time + +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +def get_js(f): + return f"""""" + +units = [ + (235, 0.0321507466), # Grams to Apothecary Ounces + (237, 5.0), # Grams to Carats + (239, 15.4323584), # Grams to Grains + (241, 0.745699872) # Horsepower to Kilowatts +] + +for eid, f in units: + data = json.dumps({'content': get_js(f)}).encode('utf-8') + url = f'https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/{eid}' + req = urllib.request.Request(url, data=data, headers=headers, method='PUT') + try: + urllib.request.urlopen(req) + print(f"Patched {eid}") + except Exception as e: + print(f"Error {eid}: {e}") + time.sleep(1) diff --git a/patch_universal.py b/patch_universal.py new file mode 100644 index 0000000..c1f19b1 --- /dev/null +++ b/patch_universal.py @@ -0,0 +1,304 @@ +import urllib.request +import json +import base64 +import time +import re + +url_base_kadence = "https://howdoyouconvert.com/wp-json/wp/v2/kadence_element/" +creds = base64.b64encode(b"ben:6YGf wVxu gBpz pkqx BGZO lfVP").decode("utf-8") +headers = { + "Content-Type": "application/json", + "Authorization": "Basic " + creds, + "User-Agent": "Mozilla/5.0" +} + +def get_robust_js(factor, offset): + return f"""""" + +# Complex mapping (same as before) +complex_fixes_by_slug = { + "ascii-to-binary": """""", + "binary-to-ascii": """""", + "binary-to-decimal": """""", + "binary-to-hex": """""", + "amps-to-volts": """""", + "amps-to-watts": """""", + "amps-to-kilowatts": """""", + "amps-to-kva": """""" +} + +def patch_element(eid, js): + print(f"Patching EID {eid}...") + data = {"content": js} + req = urllib.request.Request(f"{url_base_kadence}{eid}", data=json.dumps(data).encode("utf-8"), headers=headers, method="PUT") + try: + urllib.request.urlopen(req, timeout=30) + print("--> Done") + except Exception as e: + print(f"--> Error: {e}") + +# 1. Load factors from registry +registry = {} +with open("calculators_list.md", "r") as f: + for line in f: + if "|" not in line or "Calculators Registry" in line or "---" in line: continue + parts = [p.strip() for p in line.split("|")] + if len(parts) < 6: continue + slug = parts[4].replace("-2", "") + factor_str = parts[5] + registry[slug] = factor_str + +# 2. Load mapping +with open("/tmp/element_mapping.json", "r") as f: + mappings = json.load(f) + +for m in mappings: + eid = m['eid'] + raw_slug = m['slug'] + base_slug = raw_slug.replace("-2", "") + + if base_slug in complex_fixes_by_slug: + patch_element(eid, complex_fixes_by_slug[base_slug]) + continue + + if base_slug in registry: + factor_str = registry[base_slug] + factor = 1.0 + offset = 0.0 + + if "Linear Offset" in factor_str: + match = re.search(r'\((.*?)x \+ (.*?)\)', factor_str) + if not match: match = re.search(r'\((.*?)x - (.*?)\)', factor_str) + + if match: + m_val = match.group(1) + if m_val == "1.8": factor = 1.8 + elif m_val == "5/9": factor = 5/9 + + b_val = float(match.group(2)) + if "-" in factor_str: offset = -b_val + else: offset = b_val + else: + try: + factor = float(factor_str) + except: + print(f"Skipping {eid} ({base_slug}): unparseable factor {factor_str}") + continue + + patch_element(eid, get_robust_js(factor, offset)) + else: + print(f"Warning: Slug {base_slug} (EID {eid}) not in registry. Skipping.") + +print("UNIVERSAL PATCH COMPLETE") diff --git a/verify_batch_10.py b/verify_batch_10.py new file mode 100644 index 0000000..c1744ef --- /dev/null +++ b/verify_batch_10.py @@ -0,0 +1,46 @@ +import urllib.request +import json +import re + +batch_10_results = [ + {"url": "https://howdoyouconvert.com/calculator/megabytes-to-gigabytes/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/megajoules-to-kilowatt-hours/?ao_noptimize=1", "v1": 3.6, "expected_v2": 1, "m": 0.277778}, + {"url": "https://howdoyouconvert.com/calculator/meters-to-feet/?ao_noptimize=1", "v1": 1, "expected_v2": 3.28084, "m": 3.28084}, + {"url": "https://howdoyouconvert.com/calculator/meters-to-yards/?ao_noptimize=1", "v1": 1, "expected_v2": 1.09361, "m": 1.09361}, + {"url": "https://howdoyouconvert.com/calculator/metric-tons-to-short-tons/?ao_noptimize=1", "v1": 1, "expected_v2": 1.10231, "m": 1.10231}, + {"url": "https://howdoyouconvert.com/calculator/minutes-to-hours/?ao_noptimize=1", "v1": 60, "expected_v2": 1, "m": 0.0166667}, + {"url": "https://howdoyouconvert.com/calculator/minutes-to-seconds/?ao_noptimize=1", "v1": 1, "expected_v2": 60, "m": 60.0}, + {"url": "https://howdoyouconvert.com/calculator/nautical-miles-to-kilometers/?ao_noptimize=1", "v1": 1, "expected_v2": 1.852, "m": 1.852}, + {"url": "https://howdoyouconvert.com/calculator/newtons-to-dynes/?ao_noptimize=1", "v1": 1, "expected_v2": 100000.0, "m": 100000.0}, + {"url": "https://howdoyouconvert.com/calculator/ounces-to-grams/?ao_noptimize=1", "v1": 1, "expected_v2": 28.3495, "m": 28.3495} +] + +headers = {"User-Agent": "Mozilla/5.0"} + +for calc in batch_10_results: + print(f"\n--- Verifying {calc['url']} ---") + req = urllib.request.Request(calc['url'], headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8") + + if "initRetries" in resp and "setTimeout(init, 100)" in resp: + print("Robust JS: OK") + else: + print("Robust JS: MISSING") + + m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)' + m = re.search(m_pattern, resp) + if m: + actual_m = float(m.group(1)) + print(f"Multiplier: {actual_m} (Expected {calc['m']})") + if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.0001: + print("Math Match: OK") + else: + print("Math Match: FAIL") + else: + print("Multiplier: NOT FOUND") + + except Exception as e: + print(f"Error: {e}") + +print("\nVERIFICATION COMPLETE") diff --git a/verify_batch_7.py b/verify_batch_7.py new file mode 100644 index 0000000..5ac3345 --- /dev/null +++ b/verify_batch_7.py @@ -0,0 +1,47 @@ +import urllib.request +import json +import re + +batch_7_results = [ + {"url": "https://howdoyouconvert.com/calculator/centigrams-to-grams/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01}, + {"url": "https://howdoyouconvert.com/calculator/centiliters-to-liters/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01}, + {"url": "https://howdoyouconvert.com/calculator/centimeters-to-feet/?ao_noptimize=1", "v1": 30.48, "expected_v2": 0.99999999, "m": 0.032808399}, + {"url": "https://howdoyouconvert.com/calculator/centimeters-to-meters/?ao_noptimize=1", "v1": 100, "expected_v2": 1, "m": 0.01}, + {"url": "https://howdoyouconvert.com/calculator/centimeters-to-millimeters/?ao_noptimize=1", "v1": 1, "expected_v2": 10, "m": 10.0}, + {"url": "https://howdoyouconvert.com/calculator/chains-to-feet/?ao_noptimize=1", "v1": 1, "expected_v2": 66, "m": 66.0}, + {"url": "https://howdoyouconvert.com/calculator/chains-to-meters/?ao_noptimize=1", "v1": 1, "expected_v2": 20.1168, "m": 20.1168}, + {"url": "https://howdoyouconvert.com/calculator/cubic-centimeters-to-cubic-inches/?ao_noptimize=1", "v1": 16.387064, "expected_v2": 1, "m": 0.0610237441}, + {"url": "https://howdoyouconvert.com/calculator/cubic-feet-to-cubic-meters/?ao_noptimize=1", "v1": 35.3146667, "expected_v2": 1, "m": 0.0283168466}, + {"url": "https://howdoyouconvert.com/calculator/cubic-meters-to-liters/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0} +] + +headers = {"User-Agent": "Mozilla/5.0"} + +for calc in batch_7_results: + print(f"\n--- Verifying {calc['url']} ---") + req = urllib.request.Request(calc['url'], headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8") + + # Check for robust JS + if "initRetries" in resp and "setTimeout(init, 100)" in resp: + print("Robust JS: OK") + else: + print("Robust JS: MISSING") + + # Extract multiplier + m = re.search(r'v \* ([\d\.]+)', resp) + if m: + actual_m = float(m.group(1)) + print(f"Multiplier: {actual_m} (Expected {calc['m']})") + if abs(actual_m - calc['m']) < 0.0000001: + print("Math Match: OK") + else: + print("Math Match: FAIL") + else: + print("Multiplier: NOT FOUND") + + except Exception as e: + print(f"Error: {e}") + +print("\nVERIFICATION COMPLETE") diff --git a/verify_batch_8.py b/verify_batch_8.py new file mode 100644 index 0000000..af9be9f --- /dev/null +++ b/verify_batch_8.py @@ -0,0 +1,49 @@ +import urllib.request +import json +import re + +batch_8_results = [ + {"url": "https://howdoyouconvert.com/calculator/grams-to-micrograms/?ao_noptimize=1", "v1": 1, "expected_v2": 1000000, "m": 1000000.0}, + {"url": "https://howdoyouconvert.com/calculator/grams-to-milligrams/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0}, + {"url": "https://howdoyouconvert.com/calculator/hectopascals-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 100, "m": 100.0}, + {"url": "https://howdoyouconvert.com/calculator/hectopascals-to-millibars/?ao_noptimize=1", "v1": 1, "expected_v2": 1, "m": 1.0}, + {"url": "https://howdoyouconvert.com/calculator/joules-to-kilojoules/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/kilojoules-to-joules/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0}, + {"url": "https://howdoyouconvert.com/calculator/micrograms-to-grams/?ao_noptimize=1", "v1": 1000000, "expected_v2": 1, "m": 0.000001}, + {"url": "https://howdoyouconvert.com/calculator/milligrams-to-grams/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/millibars-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 100, "m": 100.0}, + {"url": "https://howdoyouconvert.com/calculator/millimeters-of-mercury-to-pascals/?ao_noptimize=1", "v1": 1, "expected_v2": 133.322, "m": 133.322} +] + +headers = {"User-Agent": "Mozilla/5.0"} + +for calc in batch_8_results: + print(f"\n--- Verifying {calc['url']} ---") + req = urllib.request.Request(calc['url'], headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8") + + # Check for robust JS + if "initRetries" in resp and "setTimeout(init, 100)" in resp: + print("Robust JS: OK") + else: + print("Robust JS: MISSING") + + # Extract multiplier (using flexible regex for scientific notation if needed, but here they are standard) + # Match v * factor. The factor might be 1e-06 + m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)' + m = re.search(m_pattern, resp) + if m: + actual_m = float(m.group(1)) + print(f"Multiplier: {actual_m} (Expected {calc['m']})") + if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.000001: + print("Math Match: OK") + else: + print("Math Match: FAIL") + else: + print("Multiplier: NOT FOUND") + + except Exception as e: + print(f"Error: {e}") + +print("\nVERIFICATION COMPLETE") diff --git a/verify_batch_9.py b/verify_batch_9.py new file mode 100644 index 0000000..30dbc1b --- /dev/null +++ b/verify_batch_9.py @@ -0,0 +1,48 @@ +import urllib.request +import json +import re + +batch_9_results = [ + {"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-feet-per-second/?ao_noptimize=1", "v1": 1, "expected_v2": 3.28084, "m": 3.28084}, + {"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-miles-per-hour/?ao_noptimize=1", "v1": 10, "expected_v2": 22.3694, "m": 2.23694}, + {"url": "https://howdoyouconvert.com/calculator/meters-per-second-to-yards-per-second/?ao_noptimize=1", "v1": 1, "expected_v2": 1.09361, "m": 1.09361}, + {"url": "https://howdoyouconvert.com/calculator/micrograms-to-milligrams/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/micrometers-to-millimeters/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/milligrams-to-micrograms/?ao_noptimize=1", "v1": 1, "expected_v2": 1000, "m": 1000.0}, + {"url": "https://howdoyouconvert.com/calculator/milliliters-to-liters/?ao_noptimize=1", "v1": 1000, "expected_v2": 1, "m": 0.001}, + {"url": "https://howdoyouconvert.com/calculator/milliliters-to-fluid-ounces/?ao_noptimize=1", "v1": 100, "expected_v2": 3.3814, "m": 0.033814}, + {"url": "https://howdoyouconvert.com/calculator/millimeters-to-centimeters/?ao_noptimize=1", "v1": 10, "expected_v2": 1, "m": 0.1}, + {"url": "https://howdoyouconvert.com/calculator/millimeters-to-inches/?ao_noptimize=1", "v1": 25.4, "expected_v2": 1, "m": 0.0393701} +] + +headers = {"User-Agent": "Mozilla/5.0"} + +for calc in batch_9_results: + print(f"\n--- Verifying {calc['url']} ---") + req = urllib.request.Request(calc['url'], headers=headers) + try: + resp = urllib.request.urlopen(req, timeout=30).read().decode("utf-8") + + # Check for robust JS + if "initRetries" in resp and "setTimeout(init, 100)" in resp: + print("Robust JS: OK") + else: + print("Robust JS: MISSING") + + # Extract multiplier + m_pattern = r'i2\.value = parseFloat\(\(v \* ([\d\.e\-]+)\)' + m = re.search(m_pattern, resp) + if m: + actual_m = float(m.group(1)) + print(f"Multiplier: {actual_m} (Expected {calc['m']})") + if abs(actual_m - calc['m']) / (calc['m'] or 1) < 0.000001: + print("Math Match: OK") + else: + print("Math Match: FAIL") + else: + print("Multiplier: NOT FOUND") + + except Exception as e: + print(f"Error: {e}") + +print("\nVERIFICATION COMPLETE")