summaryrefslogtreecommitdiff
path: root/app/scrapers/nishieifuku-jam.ts
diff options
context:
space:
mode:
authoryyamashita <yyamashita@mosquit.one>2026-05-07 19:27:50 +0900
committeryyamashita <yyamashita@mosquit.one>2026-05-07 19:27:50 +0900
commitd5e975b601e70adf901c8e1eb7e61f0388941195 (patch)
treef1778ff15b6540b44c354cb76c44aac795448c4a /app/scrapers/nishieifuku-jam.ts
parentbffc2c74408ff7163cea0c0392dfc4b15c620a5f (diff)
Add 5 new venue scrapers; extract artist info for WARP, shibuya-o, MOON STEP, mod
New scrapers: Fever 下北沢, Nine Spices 下北沢, 西荻窪 JAM, mod 柴崎, 中野 MOON STEP Artist extraction added/fixed: - warp-kichijoji: parse div.w-flyer (clone + remove nested notes-wrapper) - shibuya-o: rewrite to scrape each sub-venue; artist from li.p-scheduled-card__artist-item - moon-step-nakano: parse 出演 section from WordPress API description HTML - mod-shibasaki: fetch individual event pages in parallel; handle live:/出演:/・ bullet formats Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'app/scrapers/nishieifuku-jam.ts')
-rw-r--r--app/scrapers/nishieifuku-jam.ts75
1 files changed, 75 insertions, 0 deletions
diff --git a/app/scrapers/nishieifuku-jam.ts b/app/scrapers/nishieifuku-jam.ts
new file mode 100644
index 0000000..c93b051
--- /dev/null
+++ b/app/scrapers/nishieifuku-jam.ts
@@ -0,0 +1,75 @@
+/**
+ * 西永福JAM — https://jam.rinky.info/events
+ *
+ * rinky.info プラットフォーム。meets-otsuka と同じ HTML 構造。
+ * <div class="blog-entry event-wrap" event-date="YYYY-MM-DD">
+ * <h2><a href="/events/ID">タイトル</a></h2>
+ * <p class="act"><span>アーティスト</span></p>
+ * <p class="time">OPEN 18:30 / START 19:00</p>
+ * <span class="ticket-price__label">価格</span>
+ */
+import * as cheerio from "cheerio";
+import type { Scraper, VenueMeta } from "./base";
+import type { EventInput } from "~/lib/db.server";
+
+export const venue: VenueMeta = {
+ id: "nishieifuku-jam",
+ name: "西永福JAM",
+ url: "https://jam.rinky.info",
+ area: "西永福",
+};
+
+export const scraper: Scraper = {
+ venue,
+ async scrape(): Promise<EventInput[]> {
+ const res = await fetch("https://jam.rinky.info/events");
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ const $ = cheerio.load(await res.text());
+ const events: EventInput[] = [];
+
+ $("div.blog-entry.event-wrap").each((_, el) => {
+ const $el = $(el);
+
+ const date = $el.attr("event-date") ?? "";
+ if (!date.match(/^\d{4}-\d{2}-\d{2}$/)) return;
+
+ const $link = $el.find("h2 a").first();
+ const title = $link.text().trim();
+ if (!title) return;
+
+ const detailPath = $link.attr("href") ?? null;
+ const sourceUrl = detailPath ? `${venue.url}${detailPath}` : null;
+
+ const artist = $el.find("p.act span").map((_, s) => $(s).text().trim()).get().join("、") || null;
+
+ const timeText = $el.find("p.time").first().text();
+ const openMatch = timeText.match(/OPEN\s*(\d{2}:\d{2})/i);
+ const startMatch = timeText.match(/START\s*(\d{2}:\d{2})/i);
+
+ const price = $el.find("span.ticket-price__label").first().text().trim() || null;
+
+ const bgStyle = $el.find("div.image-bg").attr("style") ?? "";
+ const imgMatch = bgStyle.match(/url\(["']?([^"')]+)["']?\)/);
+ const imageUrl = imgMatch?.[1] ?? null;
+
+ const ticketUrl =
+ $el.find("a[href*='livepocket'], a[href*='eplus'], a[href*='pia'], a[href*='ticket'], a[href*='tiget']")
+ .first().attr("href") ?? null;
+
+ events.push({
+ venue_id: venue.id,
+ title,
+ artist,
+ date,
+ open_time: openMatch?.[1] ?? null,
+ start_time: startMatch?.[1] ?? null,
+ price,
+ ticket_url: ticketUrl,
+ image_url: imageUrl,
+ source_url: sourceUrl,
+ });
+ });
+
+ return events;
+ },
+};