#!/usr/bin/env python3 """Static generator for helpme.tips — arbitrage-ready content site. Articles are multi-page (pagination = more ad impressions per session). Python 3.6 stdlib only. Ad slots are emitted as comments plus empty mount divs; the fleet ad wrapper fills them. """ import json, os, shutil, html, datetime ROOT = os.path.dirname(os.path.abspath(__file__)) SITE_DIR = os.path.join(ROOT, 'site') STATIC = os.path.join(ROOT, 'static') SITE_URL = 'https://helpme.tips' SITE_NAME = 'Help Me Tips' YEAR = datetime.date.today().year def esc(s): return html.escape(s, quote=True) def load_articles(): with open(os.path.join(ROOT, 'content', 'articles.json')) as f: arts = json.load(f) for i, a in enumerate(arts): a['id'] = i return arts def layout(title, desc, body, path='/', extra_head=''): return f""" {esc(title)} {extra_head}
{body}
""" def article_card(a): return f""" {esc(a['category'])}

{esc(a['title'])}

{esc(a['dek'])}

{a['pages_count']} pages · {a.get('read_min', 4)} min read
""" def page_index(articles): cards = ''.join(article_card(a) for a in articles) body = f"""

Tips that actually help.

Short, practical guides for everyday problems — kitchen, sleep, coffee, habits, home and your phone. No fluff, no 800-word intros.

Latest tips

{cards}

Why Help Me Tips?

Most tip articles online bury one useful sentence under a wall of filler. We do the opposite: every page is a tight, actionable list you can finish with your coffee. New guides are added every week across home, kitchen, sleep, tech and habits.

""" title = 'Help Me Tips — Practical Everyday Tips That Actually Help' desc = ('Short, practical guides for everyday life: kitchen shortcuts, better sleep, ' 'coffee, phone settings, habits and home. New tips weekly.') return layout(title, desc, body, '/') def page_article(a, page_idx, total): pg = a['pages'][page_idx] parts = [] if pg.get('heading'): parts.append('

%s

' % esc(pg['heading'])) parts += ['

%s

' % esc(p) for p in pg['paras']] for h, paras in pg.get('sections', []): parts.append('

%s

' % esc(h)) parts += ['

%s

' % esc(p) for p in paras] # multi-item list support content = '\n'.join(parts) nav = [] if page_idx > 0: prev = '/tips/%s/' % a['slug'] if page_idx == 1 else '/tips/%s/%d/' % (a['slug'], page_idx) nav.append('← Previous' % prev) nav.append('Page %d of %d' % (page_idx + 1, total)) if page_idx < total - 1: nav.append('Next page →' % (a['slug'], page_idx + 2)) nav_html = '
%s
' % '\n'.join(nav) dots = '
%s
' % ''.join( '' % ('on' if i == page_idx else '') for i in range(total)) body = f"""

{esc(a['title'])}

{esc(a['dek'])}

{a.get('updated', '')} · Page {page_idx + 1} of {total} · {a.get('read_min', 4)} min read

{content}
{dots} {nav_html}

Keep reading

{more_cards(a, articles_all)}
""" suffix = '' if page_idx == 0 else ' (Page %d)' % (page_idx + 1) title = '%s%s — Help Me Tips' % (a['title'], suffix) desc = a['dek'] ld = {"@context": "https://schema.org", "@type": "Article", "headline": a['title'], "description": a['dek'], "mainEntityOfPage": SITE_URL + '/tips/%s/' % a['slug'], "datePublished": a.get('updated', '2026-09-16')} extra = '' % esc(json.dumps(ld)) path = '/tips/%s/' % a['slug'] if page_idx == 0 else '/tips/%s/%d/' % (a['slug'], page_idx + 1) return layout(title, desc, body, path, extra) def more_cards(current, all_arts): others = [a for a in all_arts if a['slug'] != current['slug']][:4] return ''.join(article_card(a) for a in others) articles_all = [] # populated in build(); used by more_cards def page_about(): body = """

About Help Me Tips

Help Me Tips publishes short, practical guides for everyday problems. We believe a good tip article should respect your time: clear steps, no 800-word personal essays, no product pitches.

Topics we cover: kitchen and cooking shortcuts, sleep quality, coffee, phone and tech settings, home care, and small habits that compound.

Our editorial standard

""" return layout('About — Help Me Tips', 'What Help Me Tips is and how we pick tips.', body, '/about/') def page_contact(): body = """

Contact

Tip ideas, corrections, feedback? We read everything: hello@helpme.tips

""" return layout('Contact — Help Me Tips', 'Contact Help Me Tips.', body, '/contact/') def page_privacy(): body = """

Privacy Policy

Last updated: %s

Help Me Tips collects standard web server logs (IP address, browser type, pages visited) for security and aggregate statistics. We do not require accounts and do not collect names or emails.

Cookies and advertising

We display advertising to keep this site free. Advertising partners, which may include Google, use cookies and similar technologies to serve ads based on your prior visits to this and other websites. You may opt out of personalized advertising at Google Ads Settings or aboutads.info.

Where required by law (EEA/UK), a consent banner will let you accept or reject non-essential cookies, and your choice will be honored.

Data sharing

We do not sell personal information. Analytics, if used, are aggregate and not identifiable.

Contact

Questions: hello@helpme.tips

""" % datetime.date.today().strftime('%B %d, %Y') return layout('Privacy Policy — Help Me Tips', 'Privacy policy for helpme.tips.', body, '/privacy-policy/') def page_terms(): body = """

Terms of Use

Last updated: %s

By using helpme.tips you agree to these terms. Content is provided for general information only and is not professional, medical, legal or financial advice. Use tips at your own discretion.

Use of content

Personal, non-commercial use only. Bulk republication requires written permission.

No warranties

The site is provided "as is" without warranties of any kind. Results of following tips may vary.

Contact

Questions: hello@helpme.tips

""" % datetime.date.today().strftime('%B %d, %Y') return layout('Terms of Use — Help Me Tips', 'Terms for helpme.tips.', body, '/terms/') def page_404(): body = """

404

That page slipped out of the tips drawer.

Back to all tips →

""" return layout('404 — Help Me Tips', 'Page not found.', body, '/404.html') def write(path, content): full = os.path.join(SITE_DIR, path) os.makedirs(os.path.dirname(full) or SITE_DIR, exist_ok=True) with open(full, 'w') as f: f.write(content) def build(): global articles_all if os.path.exists(SITE_DIR): shutil.rmtree(SITE_DIR) os.makedirs(SITE_DIR) st = os.path.join(SITE_DIR, 'static') os.makedirs(st, exist_ok=True) for fn in os.listdir(STATIC): shutil.copy(os.path.join(STATIC, fn), st) articles = load_articles() articles_all = articles articles.sort(key=lambda a: a.get('updated', ''), reverse=True) for a in articles: a['pages_count'] = len(a['pages']) write('index.html', page_index(articles)) n_pages = 0 for a in articles: total = len(a['pages']) a['pages_count'] = total for i in range(total): write('tips/%s/index.html' % a['slug'] if i == 0 else 'tips/%s/%d/index.html' % (a['slug'], i + 1), page_article(a, i, total)) n_pages += 1 write('about/index.html', page_about()) write('contact/index.html', page_contact()) write('privacy-policy/index.html', page_privacy()) write('terms/index.html', page_terms()) write('404.html', page_404()) pages = ['/', '/about/', '/contact/', '/privacy-policy/', '/terms/'] + \ ['/tips/%s/' % a['slug'] for a in articles] today = datetime.date.today().isoformat() sm = ['', ''] for p in pages: sm.append('%s%s%s' % (SITE_URL, p, today)) sm.append('') write('sitemap.xml', '\n'.join(sm)) write('robots.txt', 'User-agent: *\nAllow: /\n\nSitemap: %s/sitemap.xml\n' % SITE_URL) nfiles = sum(len(fn) for _, _, fn in os.walk(SITE_DIR)) total_bytes = sum(os.path.getsize(os.path.join(dp, f)) for dp, _, fn in os.walk(SITE_DIR) for f in fn) print('Built %d files (%d article pages, %d articles) -> %s (%d bytes)' % (nfiles, n_pages, len(articles), SITE_DIR, total_bytes)) if __name__ == '__main__': build()