Skip to content

Instantly share code, notes, and snippets.

@BeSpunky
Created May 27, 2023 07:36
Show Gist options
  • Save BeSpunky/10cffec294452dccb4a65cebef9d0b38 to your computer and use it in GitHub Desktop.
Save BeSpunky/10cffec294452dccb4a65cebef9d0b38 to your computer and use it in GitHub Desktop.
// Name: Show Scraped Apartments
import '@johnlindquist/kit';
import { Choice } from '@johnlindquist/kit';
import { z } from 'zod';
const ScrapedItemSchema = z.object({
id: z.string(),
address: z.string(),
neighborhood: z.string().optional(),
city: z.string().optional(),
price: z.number(),
description: z.string(),
imageUrl: z.string(),
scrapeDate: z.date()
});
const AnalyzedItemSchema = z.object({
id: z.string(),
score: z.number(),
explanation: z.string(),
analysisDate: z.date(),
hide: z.boolean().optional()
});
const ScrapedItemMapSchema = z.record(z.string(), ScrapedItemSchema);
const AnalyzedItemListSchema = z.array(AnalyzedItemSchema);
const apartments = await db('_apartment-scraper', { scraped: {} as z.infer<typeof ScrapedItemMapSchema>, analyzed: [] as z.infer<typeof AnalyzedItemListSchema> });
const scoreAsStars = (score: number) => '⭐'.repeat(Math.round(score / 2));
const scaledImageUrl = (url: string) => url.replace(/w=\d&h=\d/, 'w=1000&h=1000').replace(/c=\d/, 'c=0');
const previewApartment = (scraped: z.infer<typeof ScrapedItemSchema>, analyzed: z.infer<typeof AnalyzedItemSchema>) => /*html*/`
<div class="flex flex-col" style="gap: 10px">
<div dir="rtl">
<h2>${ scraped.address } (${ scraped.price }₪)</h2>
<h4>${ scraped.neighborhood }, ${ scraped.city }</h4>
<p>${ scraped.description }</p>
</div>
<div>
<h2 class="text-center">Analysis</h2>
<p>${ scoreAsStars(analyzed.score) } ${ analyzed.score }</p>
<p>Explanation: ${ analyzed.explanation }</p>
<img class="w-full" src="${ scaledImageUrl(scraped.imageUrl) }" />
</div>
</div>
`;
const apartmentById = (id: string) => apartments.scraped[id];
const hideApartment = async (id: string) =>
{
const whyNot = await mini('Why are you hiding this apartment?');
Object.assign(apartments.analyzed.find(a => a.id === id)!, { hide: true, whyNot });
await apartments.write();
main(); // Previously hidden by the explanation prompt
};
const createChoices = () => apartments.analyzed.filter(a => !a.hide).map(a => ({
html: /*html*/`
<!-- Create a tailwind defined template to display a list item for the apartment, which includes: the address, description, score as star emojis-->
<div class="flex flex-col relative p-2 overflow-x-auto" dir="rtl">
<h2 class="text-right">${ apartmentById(a.id).address } <small>${ scoreAsStars(a.score) } (${ a.score })</small></h2>
<p class="text-sm">${ apartmentById(a.id).description }</p>
</div>
`,
id: a.id,
name: apartmentById(a.id).address,
description: apartmentById(a.id).description,
className: 'p-2',
value: a,
preview: () => previewApartment(apartments.scraped[a.id], a)
}) satisfies Choice<typeof a>);
let lastChoiceId = '';
async function main()
{
while (true)
{
const choice = await arg({
placeholder: 'Choose an apartment',
ignoreBlur: true,
defaultChoiceId: lastChoiceId,
x: 0, y: 0,
height: 1500,
width: 1000,
shortcuts: [
{
key: 'delete',
name: 'Hide apartment',
bar: 'right',
onPress(_, state)
{
if (!state.focused) return;
return hideApartment(state.focused.id!);
}
}
]
}, createChoices);
const apartment = { ...choice, ...apartments.scraped[choice.id] };
lastChoiceId = choice.id;
open(`https://www.yad2.co.il/item/${ apartment.id }`);
}
};
await main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment