Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ tests/fixtures/real-pages/*.json
tests/fixtures/real-pages/*.png
tests/fixtures/real-pages/reports/
tests/fixtures/ui/
tmp/
2 changes: 1 addition & 1 deletion PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Eventy processes webpage or selected text only when you use the "Scan" action. T

Data handling:

- No third-party trackers are embedded. We do not sell or share your personal information.
- The extension does not embed third-party trackers. Website visits may appear in Cloudflare traffic measurement for basic site delivery and abuse prevention. We do not sell or share your personal information.
- Minimal Google scope used: https://www.googleapis.com/auth/calendar.events (create events only).
- **BYOK (Bring Your Own Key):** If you provide your own OpenRouter API key, it is transmitted securely via our Cloudflare Worker proxy to authenticate your requests. We do not store your API key on our servers; it is passed through to OpenRouter.
- **Image Scanning:** Images you choose to scan are processed by our proxy and LLM provider to extract event details. We do not store these images.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Eventy is a Chrome extension that finds event details on webpages, images, and pasted text, then turns them into calendar-ready entries.

Version: v1.2.0
Version: v1.2.1

Homepage: https://eventy.ariobarin.com/

Expand Down Expand Up @@ -102,8 +102,8 @@ npm run deploy:home

## Legal

- [Privacy Policy](https://ariobarin.github.io/Eventy/privacy.html)
- [Terms of Service](https://ariobarin.github.io/Eventy/terms.html)
- [Privacy Policy](https://eventy.ariobarin.com/privacy.html)
- [Terms of Service](https://eventy.ariobarin.com/terms.html)

## License

Expand Down
2 changes: 1 addition & 1 deletion TERMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Effective date: 2026-01-26
- Minimal Google scope used: https://www.googleapis.com/auth/calendar.events (create events only, when enabled).
- **API Keys (BYOK):** Users providing their own API keys depend on OpenRouter services. We facilitate the request but are not responsible for OpenRouter availability.
- Tokens are obtained via Chrome Identity; Eventy does not store tokens on our servers.
- See Privacy Policy for more details: https://ariobarin.github.io/Eventy/privacy.html.
- See Privacy Policy for more details: https://eventy.ariobarin.com/privacy.html.

4. Availability and changes

Expand Down
Binary file added docs/assets/eventy-social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
163 changes: 161 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,47 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Eventy</title>
<meta name="description" content="Turn pages, text, and images into calendar events.">
<title>Eventy: AI event extractor for any calendar</title>
<meta name="description"
content="Eventy is a Chrome extension that turns web pages, selected text, emails, flyers, or screenshots into Google Calendar or iCalendar events with AI.">
<link rel="canonical" href="https://eventy.ariobarin.com/">
<link rel="icon" type="image/png" sizes="128x128" href="./assets/icon128.png">
<link rel="apple-touch-icon" href="./assets/icon128.png">
<meta property="og:title" content="Eventy: AI event extractor for any calendar">
<meta property="og:description"
content="Eventy is a Chrome extension that turns web pages, selected text, emails, flyers, or screenshots into Google Calendar or iCalendar events with AI.">
<meta property="og:url" content="https://eventy.ariobarin.com/">
<meta property="og:type" content="website">
<meta property="og:image" content="https://eventy.ariobarin.com/assets/eventy-social-preview.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Eventy turning page details into a calendar event">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Eventy: AI event extractor for any calendar">
<meta name="twitter:description"
content="Eventy is a Chrome extension that turns web pages, selected text, emails, flyers, or screenshots into Google Calendar or iCalendar events with AI.">
<meta name="twitter:image" content="https://eventy.ariobarin.com/assets/eventy-social-preview.png">
<meta name="twitter:image:alt" content="Eventy turning page details into a calendar event">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Eventy",
"description": "Eventy is a Chrome extension that turns web pages, selected text, emails, flyers, or screenshots into Google Calendar or iCalendar events with AI.",
"url": "https://eventy.ariobarin.com/",
"applicationCategory": "UtilitiesApplication",
"operatingSystem": "Chrome",
"browserRequirements": "Requires Google Chrome or a Chromium-based browser",
"downloadUrl": "https://chromewebstore.google.com/detail/eventy/kfancgcbhdkeohknmidbnioccmmoknjl",
"softwareVersion": "1.2.1",
"image": "https://eventy.ariobarin.com/assets/eventy-social-preview.png",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
}
}
</script>
<style>
:root {
color-scheme: light;
Expand Down Expand Up @@ -383,6 +419,66 @@
color: var(--green);
}

.content-band {
width: min(1120px, calc(100% - 40px));
margin: 0 auto;
padding: 18px 0 28px;
}

.section-title {
max-width: 680px;
margin: 0 0 22px;
font-size: 1.52rem;
line-height: 1.28;
}

.section-copy {
max-width: 720px;
margin: 0 0 24px;
color: #3f4956;
font-size: 1rem;
line-height: 1.75;
}

.feature-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1px;
border: 1px solid var(--line);
background: var(--line);
}

.feature-item {
min-height: 176px;
padding: 24px;
background: rgba(255, 255, 255, 0.86);
}

.feature-item h3 {
margin: 0 0 10px;
font-size: 1.02rem;
line-height: 1.3;
}

.feature-item p {
margin: 0;
color: #4b5563;
line-height: 1.65;
}

.support-row {
display: flex;
flex-wrap: wrap;
gap: 12px 22px;
margin-top: 12px;
}

.support-row a {
color: var(--blue);
font-weight: 780;
text-underline-offset: 4px;
}

footer {
width: min(1120px, calc(100% - 40px));
margin: 0 auto;
Expand Down Expand Up @@ -461,6 +557,7 @@
@media (max-width: 560px) {
.site-header,
.hero-inner,
.content-band,
footer {
width: min(100% - 28px, 540px);
}
Expand Down Expand Up @@ -529,6 +626,15 @@
.calendar-grid {
gap: 5px;
}

.feature-grid {
grid-template-columns: 1fr;
}

.feature-item {
min-height: auto;
padding: 20px;
}
}

</style>
Expand Down Expand Up @@ -616,6 +722,59 @@ <h1 id="eventy-title">Eventy</h1>

</div>
</section>

<section class="content-band" aria-labelledby="eventy-workflow-title">
<h2 class="section-title" id="eventy-workflow-title">AI event extraction for the places plans show up.</h2>
<p class="section-copy">
Eventy is a Chrome extension for turning messy event details into calendar-ready entries. It works
from web pages, selected text, emails, flyers, screenshots, and images, then lets you review the result
before anything reaches your calendar.
</p>

<div class="feature-grid">
<article class="feature-item">
<h3>Scan web pages and selected text</h3>
<p>
Use Eventy as an AI event extractor on event pages, newsletters, email views, and posts. Scan a
full page or highlight only the text you want parsed.
</p>
</article>
<article class="feature-item">
<h3>Read flyers, screenshots, and images</h3>
<p>
Send a flyer, poster, screenshot, or event image through the extension and turn the visible
date, time, title, and location into structured event fields.
</p>
</article>
<article class="feature-item">
<h3>Review before adding</h3>
<p>
Eventy separates upcoming and past results, preserves useful details, and gives you a chance to
choose the events you want before creating anything.
</p>
</article>
<article class="feature-item">
<h3>Export to Google Calendar or iCalendar</h3>
<p>
Add selected events to Google Calendar or download iCalendar files for Apple Calendar, Outlook,
iCloud, and other calendars that understand .ics files.
</p>
</article>
</div>
</section>

<section class="content-band" aria-labelledby="eventy-privacy-title">
<h2 class="section-title" id="eventy-privacy-title">Privacy and control stay part of the workflow.</h2>
<p class="section-copy">
Eventy scans only when you ask it to scan. You can use the shared service or bring your own OpenRouter
key, review extracted details before export, and disconnect Google Calendar access from the extension
settings at any time.
</p>
<div class="support-row" aria-label="Support links">
<a href="https://github.com/ariobarin/Eventy/issues">Report an issue on GitHub</a>
<a href="mailto:eventy.sup@gmail.com">eventy.sup@gmail.com</a>
</div>
</section>
</main>

<footer>
Expand Down
9 changes: 8 additions & 1 deletion docs/privacy.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Eventy Privacy Policy</title>
<meta name="description"
content="Privacy details for Eventy, the Chrome extension that turns selected content into calendar events with AI." />
<link rel="canonical" href="https://eventy.ariobarin.com/privacy.html" />
<style>
body {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial,
Expand Down Expand Up @@ -39,7 +42,11 @@ <h1>Eventy Privacy Policy</h1>
</p>
<h2>What data we handle</h2>
<ul>
<li>No third-party trackers are embedded.</li>
<li>
The extension does not embed third-party trackers. Website visits
may appear in Cloudflare traffic measurement for basic site
delivery and abuse prevention.
</li>
<li>
We do not sell or share your personal information. We do not
maintain server-side user profiles.
Expand Down
4 changes: 4 additions & 0 deletions docs/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://eventy.ariobarin.com/sitemap.xml
12 changes: 12 additions & 0 deletions docs/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://eventy.ariobarin.com/</loc>
</url>
<url>
<loc>https://eventy.ariobarin.com/privacy.html</loc>
</url>
<url>
<loc>https://eventy.ariobarin.com/terms.html</loc>
</url>
</urlset>
5 changes: 4 additions & 1 deletion docs/terms.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Eventy Terms of Service</title>
<meta name="description"
content="Terms for using Eventy to review extracted event details and add them to your calendar." />
<link rel="canonical" href="https://eventy.ariobarin.com/terms.html" />
<style>
body {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial,
Expand Down Expand Up @@ -69,7 +72,7 @@ <h2>3. Permissions and data use</h2>
tokens on our servers.
</li>
<li>
See the <a href="https://ariobarin.github.io/Eventy/privacy.html">Privacy Policy</a> for details
See the <a href="https://eventy.ariobarin.com/privacy.html">Privacy Policy</a> for details
on data handling.
</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Eventy",
"description": "Extract events from any webpage into Google Calendar or iCloud Calendar with one click.",
"version": "1.2.0",
"version": "1.2.1",
"manifest_version": 3,
"action": {
"default_popup": "src/ui/index.html",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eventy",
"version": "1.2.0",
"version": "1.2.1",
"description": "Chrome extension that turns webpages, images, and pasted text into calendar events.",
"type": "module",
"license": "MIT",
Expand Down
55 changes: 55 additions & 0 deletions scripts/verify-extension-ui.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,61 @@ async function main() {
return { open: openEvidence, restored, scanned };
});

await runCase(results, "iCalendar download shows open-file guidance", async () => {
await clearExtensionStorage(browser, extensionId);
const page = await browser.newPage();
await page.goto(`${fixtureServer.origin}/event-page.html`, {
waitUntil: "domcontentloaded",
});
const popup = await openExtensionPopup(browser, page, extensionId, extension);
const popupDiagnostics = await attachPageDiagnostics(popup, "icalendar-popup");
await waitForScanAvailability(popup);
await popup.evaluate(async () => {
await chrome.storage.sync.set({
settings: {
defaultCalendar: "icloud",
},
});
});

await popup.click("#scanBtn");
await waitForVisibleResults(popup);

const firstCardPoint = await popup.$eval(".event-card", (card) => {
card.scrollIntoView({ block: "center", inline: "nearest" });
const rect = card.getBoundingClientRect();
return {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
};
});
await popup.mouse.click(firstCardPoint.x, firstCardPoint.y);
await popup.waitForFunction(
() => document.querySelectorAll(".event-card.selected").length === 1 &&
document.getElementById("addSelectedBtn")?.disabled === false,
{ timeout: options.timeoutMs }
);

await popup.click("#addSelectedBtn");
await popup.waitForFunction(
() => {
const toast = document.getElementById("toast");
return toast?.classList.contains("visible") &&
toast.innerText.includes("After it downloads, open the .ics file");
},
{ timeout: options.timeoutMs }
);

const notice = await captureEvidence(popup, reportDir, "icalendar-download-notice");
assert.equal(notice.state.toast.visible, true);
assert.match(notice.state.toast.text, /After it downloads, open the \.ics file/);
assertNoPopupOverflow(notice.state);
assertNoUnexpectedErrors(popupDiagnostics);
await closePage(popup);
await closePage(page);
return notice;
});

await runCase(results, "settings button opens usable settings page", async () => {
await clearExtensionStorage(browser, extensionId);
const page = await browser.newPage();
Expand Down
Loading