aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bemani/sdvx.py76
-rw-r--r--constants.py2
-rw-r--r--generate.py2
-rw-r--r--middleware/package.json2
-rw-r--r--middleware/pnpm-lock.yaml94
-rw-r--r--middleware/public/favicon.icobin25931 -> 15406 bytes
-rw-r--r--middleware/src/app/[gameName]/page.tsx28
-rw-r--r--news_feed.py4
-rw-r--r--site/src/pages/Homepage.tsx6
-rw-r--r--summarizer.py2
10 files changed, 158 insertions, 58 deletions
diff --git a/bemani/sdvx.py b/bemani/sdvx.py
index 9d5a33b..5a7d25c 100644
--- a/bemani/sdvx.py
+++ b/bemani/sdvx.py
@@ -49,3 +49,79 @@ def parse_exceed_gear_news_site(html: str):
})
return entries
+
+def parse_nabla_news_site(html: str):
+ base_url = "https://p.eagate.573.jp"
+ soup = BeautifulSoup(html, 'html.parser')
+ news_list = soup.select('#news-inner ul.news li')
+
+ entries = []
+ for li in news_list:
+ strong_tags = li.select('strong')
+ if not strong_tags:
+ continue
+
+ date = strong_tags[0]
+ date_str = date.text.strip()
+ try:
+ dt = datetime.strptime(date_str, "%Y.%m.%d")
+ timestamp = int(dt.timestamp())
+ except ValueError:
+ timestamp = None
+
+ headline_text = None
+ if len(strong_tags) > 1:
+ headline_text = strong_tags[1].text.strip()
+
+ for tag in li.select('font, b, u, span'):
+ tag.unwrap()
+
+ content_parts = []
+ for node in li.contents:
+ if hasattr(node, 'name'):
+ if node.name == 'strong':
+ continue
+ elif node.name == 'br':
+ content_parts.append('\n')
+ elif node.name == 'a' and 'link-text' in node.get('class', []):
+ content_parts.append(node.text.strip())
+ elif node.name not in ['img']: # Skip image tags for content
+ content_parts.append(node.get_text(strip=True))
+ else:
+ text = str(node).strip()
+ if text and text not in [date_str, headline_text]:
+ content_parts.append(text)
+
+ content = '\n'.join(filter(None, content_parts)).strip()
+
+ images = []
+ for img in li.select('img'):
+ src = img.get('data-original') or img.get('src')
+ if not src or (isinstance(src, str) and src.startswith('data:')):
+ continue
+ if isinstance(src, str):
+ src = urljoin(base_url, src)
+ parent = img.find_parent('a')
+ href = None
+ if parent and hasattr(parent, 'get') and parent.get('href'):
+ href_val = parent.get('href')
+ if isinstance(href_val, str):
+ href = urljoin(base_url, href_val)
+
+ image_entry = {'image': src, 'link': href}
+ if image_entry not in images:
+ images.append(image_entry)
+
+ entries.append({
+ 'date': date_str,
+ 'identifier': 'SOUND_VOLTEX',
+ 'type': None,
+ 'timestamp': timestamp,
+ 'headline': headline_text,
+ 'content': content,
+ "url": None,
+ 'images': images,
+ 'is_ai_summary': False
+ })
+
+ return entries
diff --git a/constants.py b/constants.py
index dc1c680..06b752c 100644
--- a/constants.py
+++ b/constants.py
@@ -2,7 +2,7 @@ from enum import Enum
DAYS_LIMIT=14
-SOUND_VOLTEX_EXCEED_GEAR_NEWS_SITE ="https://p.eagate.573.jp/game/sdvx/vi/news/index.html"
+SOUND_VOLTEX_NABLA_NEWS_SITE="https://p.eagate.573.jp/game/sdvx/vii/news/index.html"
POLARIS_CHORD_NEWS_SITE="https://p.eagate.573.jp/game/polarischord/pc/news/news.html"
POLARIS_CHORD_RECENT_NEWS_LIMIT=15
diff --git a/generate.py b/generate.py
index 819ce08..79c8f11 100644
--- a/generate.py
+++ b/generate.py
@@ -162,7 +162,7 @@ def generate_iidx_news_file():
return news
def generate_sdvx_news_file():
- news = generate_news_file("sdvx_news", constants.SOUND_VOLTEX_EXCEED_GEAR_NEWS_SITE)
+ news = generate_news_file("sdvx_news", constants.SOUND_VOLTEX_NABLA_NEWS_SITE)
attempt_broadcast_notifications(news, "New Information for SOUND VOLTEX","sdvx")
return news
diff --git a/middleware/package.json b/middleware/package.json
index b54eb7a..cf4f007 100644
--- a/middleware/package.json
+++ b/middleware/package.json
@@ -20,7 +20,7 @@
"eslint": "9.30.0",
"eslint-config-next": "15.3.4",
"global": "^4.4.0",
- "next": "^15.3.4",
+ "next": "15.3.6",
"postcss": "^8.5.6",
"react": "19.1.0",
"react-dom": "19.1.0",
diff --git a/middleware/pnpm-lock.yaml b/middleware/pnpm-lock.yaml
index 2e2f6e2..f82b66e 100644
--- a/middleware/pnpm-lock.yaml
+++ b/middleware/pnpm-lock.yaml
@@ -13,7 +13,7 @@ importers:
version: 0.15.15
'@next/font':
specifier: 14.2.15
- version: 14.2.15(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
+ version: 14.2.15(next@15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
'@types/node':
specifier: 24.0.8
version: 24.0.8
@@ -28,7 +28,7 @@ importers:
version: 1.35.4
'@vercel/analytics':
specifier: ^1.5.0
- version: 1.5.0(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
+ version: 1.5.0(next@15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
'@vercel/og':
specifier: ^0.6.8
version: 0.6.8
@@ -42,8 +42,8 @@ importers:
specifier: ^4.4.0
version: 4.4.0
next:
- specifier: ^15.3.4
- version: 15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ specifier: 15.3.6
+ version: 15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
postcss:
specifier: ^8.5.6
version: 8.5.6
@@ -340,8 +340,8 @@ packages:
'@neon-rs/load@0.0.4':
resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==}
- '@next/env@15.3.4':
- resolution: {integrity: sha512-ZkdYzBseS6UjYzz6ylVKPOK+//zLWvD6Ta+vpoye8cW11AjiQjGYVibF0xuvT4L0iJfAPfZLFidaEzAOywyOAQ==}
+ '@next/env@15.3.6':
+ resolution: {integrity: sha512-/cK+QPcfRbDZxmI/uckT4lu9pHCfRIPBLqy88MhE+7Vg5hKrEYc333Ae76dn/cw2FBP2bR/GoK/4DU+U7by/Nw==}
'@next/eslint-plugin-next@15.3.4':
resolution: {integrity: sha512-lBxYdj7TI8phbJcLSAqDt57nIcobEign5NYIKCiy0hXQhrUbTqLqOaSDi568U6vFg4hJfBdZYsG4iP/uKhCqgg==}
@@ -351,50 +351,50 @@ packages:
peerDependencies:
next: '*'
- '@next/swc-darwin-arm64@15.3.4':
- resolution: {integrity: sha512-z0qIYTONmPRbwHWvpyrFXJd5F9YWLCsw3Sjrzj2ZvMYy9NPQMPZ1NjOJh4ojr4oQzcGYwgJKfidzehaNa1BpEg==}
+ '@next/swc-darwin-arm64@15.3.5':
+ resolution: {integrity: sha512-lM/8tilIsqBq+2nq9kbTW19vfwFve0NR7MxfkuSUbRSgXlMQoJYg+31+++XwKVSXk4uT23G2eF/7BRIKdn8t8w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@next/swc-darwin-x64@15.3.4':
- resolution: {integrity: sha512-Z0FYJM8lritw5Wq+vpHYuCIzIlEMjewG2aRkc3Hi2rcbULknYL/xqfpBL23jQnCSrDUGAo/AEv0Z+s2bff9Zkw==}
+ '@next/swc-darwin-x64@15.3.5':
+ resolution: {integrity: sha512-WhwegPQJ5IfoUNZUVsI9TRAlKpjGVK0tpJTL6KeiC4cux9774NYE9Wu/iCfIkL/5J8rPAkqZpG7n+EfiAfidXA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@next/swc-linux-arm64-gnu@15.3.4':
- resolution: {integrity: sha512-l8ZQOCCg7adwmsnFm8m5q9eIPAHdaB2F3cxhufYtVo84pymwKuWfpYTKcUiFcutJdp9xGHC+F1Uq3xnFU1B/7g==}
+ '@next/swc-linux-arm64-gnu@15.3.5':
+ resolution: {integrity: sha512-LVD6uMOZ7XePg3KWYdGuzuvVboxujGjbcuP2jsPAN3MnLdLoZUXKRc6ixxfs03RH7qBdEHCZjyLP/jBdCJVRJQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-arm64-musl@15.3.4':
- resolution: {integrity: sha512-wFyZ7X470YJQtpKot4xCY3gpdn8lE9nTlldG07/kJYexCUpX1piX+MBfZdvulo+t1yADFVEuzFfVHfklfEx8kw==}
+ '@next/swc-linux-arm64-musl@15.3.5':
+ resolution: {integrity: sha512-k8aVScYZ++BnS2P69ClK7v4nOu702jcF9AIHKu6llhHEtBSmM2zkPGl9yoqbSU/657IIIb0QHpdxEr0iW9z53A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@next/swc-linux-x64-gnu@15.3.4':
- resolution: {integrity: sha512-gEbH9rv9o7I12qPyvZNVTyP/PWKqOp8clvnoYZQiX800KkqsaJZuOXkWgMa7ANCCh/oEN2ZQheh3yH8/kWPSEg==}
+ '@next/swc-linux-x64-gnu@15.3.5':
+ resolution: {integrity: sha512-2xYU0DI9DGN/bAHzVwADid22ba5d/xrbrQlr2U+/Q5WkFUzeL0TDR963BdrtLS/4bMmKZGptLeg6282H/S2i8A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-linux-x64-musl@15.3.4':
- resolution: {integrity: sha512-Cf8sr0ufuC/nu/yQ76AnarbSAXcwG/wj+1xFPNbyNo8ltA6kw5d5YqO8kQuwVIxk13SBdtgXrNyom3ZosHAy4A==}
+ '@next/swc-linux-x64-musl@15.3.5':
+ resolution: {integrity: sha512-TRYIqAGf1KCbuAB0gjhdn5Ytd8fV+wJSM2Nh2is/xEqR8PZHxfQuaiNhoF50XfY90sNpaRMaGhF6E+qjV1b9Tg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@next/swc-win32-arm64-msvc@15.3.4':
- resolution: {integrity: sha512-ay5+qADDN3rwRbRpEhTOreOn1OyJIXS60tg9WMYTWCy3fB6rGoyjLVxc4dR9PYjEdR2iDYsaF5h03NA+XuYPQQ==}
+ '@next/swc-win32-arm64-msvc@15.3.5':
+ resolution: {integrity: sha512-h04/7iMEUSMY6fDGCvdanKqlO1qYvzNxntZlCzfE8i5P0uqzVQWQquU1TIhlz0VqGQGXLrFDuTJVONpqGqjGKQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
- '@next/swc-win32-x64-msvc@15.3.4':
- resolution: {integrity: sha512-4kDt31Bc9DGyYs41FTL1/kNpDeHyha2TC0j5sRRoKCyrhNcfZ/nRQkAUlF27mETwm8QyHqIjHJitfcza2Iykfg==}
+ '@next/swc-win32-x64-msvc@15.3.5':
+ resolution: {integrity: sha512-5fhH6fccXxnX2KhllnGhkYMndhOiLOLEiVGYjP2nizqeGWkN10sA9taATlXwake2E2XMvYZjjz0Uj7T0y+z1yw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -1595,8 +1595,8 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
- next@15.3.4:
- resolution: {integrity: sha512-mHKd50C+mCjam/gcnwqL1T1vPx/XQNFlXqFIVdgQdVAFY9iIQtY0IfaVflEYzKiqjeA7B0cYYMaCrmAYFjs4rA==}
+ next@15.3.6:
+ resolution: {integrity: sha512-oI6D1zbbsh6JzzZFDCSHnnx6Qpvd1fSkVJu/5d8uluqnxzuoqtodVZjYvNovooznUq8udSAiKp7MbwlfZ8Gm6w==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true
peerDependencies:
@@ -2299,38 +2299,38 @@ snapshots:
'@neon-rs/load@0.0.4': {}
- '@next/env@15.3.4': {}
+ '@next/env@15.3.6': {}
'@next/eslint-plugin-next@15.3.4':
dependencies:
fast-glob: 3.3.1
- '@next/font@14.2.15(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
+ '@next/font@14.2.15(next@15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
dependencies:
- next: 15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ next: 15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
- '@next/swc-darwin-arm64@15.3.4':
+ '@next/swc-darwin-arm64@15.3.5':
optional: true
- '@next/swc-darwin-x64@15.3.4':
+ '@next/swc-darwin-x64@15.3.5':
optional: true
- '@next/swc-linux-arm64-gnu@15.3.4':
+ '@next/swc-linux-arm64-gnu@15.3.5':
optional: true
- '@next/swc-linux-arm64-musl@15.3.4':
+ '@next/swc-linux-arm64-musl@15.3.5':
optional: true
- '@next/swc-linux-x64-gnu@15.3.4':
+ '@next/swc-linux-x64-gnu@15.3.5':
optional: true
- '@next/swc-linux-x64-musl@15.3.4':
+ '@next/swc-linux-x64-musl@15.3.5':
optional: true
- '@next/swc-win32-arm64-msvc@15.3.4':
+ '@next/swc-win32-arm64-msvc@15.3.5':
optional: true
- '@next/swc-win32-x64-msvc@15.3.4':
+ '@next/swc-win32-x64-msvc@15.3.5':
optional: true
'@nodelib/fs.scandir@2.1.5':
@@ -2615,9 +2615,9 @@ snapshots:
dependencies:
uncrypto: 0.1.3
- '@vercel/analytics@1.5.0(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)':
+ '@vercel/analytics@1.5.0(next@15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)':
optionalDependencies:
- next: 15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ next: 15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0
'@vercel/og@0.6.8':
@@ -3646,9 +3646,9 @@ snapshots:
natural-compare@1.4.0: {}
- next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ next@15.3.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
- '@next/env': 15.3.4
+ '@next/env': 15.3.6
'@swc/counter': 0.1.3
'@swc/helpers': 0.5.15
busboy: 1.6.0
@@ -3658,14 +3658,14 @@ snapshots:
react-dom: 19.1.0(react@19.1.0)
styled-jsx: 5.1.6(react@19.1.0)
optionalDependencies:
- '@next/swc-darwin-arm64': 15.3.4
- '@next/swc-darwin-x64': 15.3.4
- '@next/swc-linux-arm64-gnu': 15.3.4
- '@next/swc-linux-arm64-musl': 15.3.4
- '@next/swc-linux-x64-gnu': 15.3.4
- '@next/swc-linux-x64-musl': 15.3.4
- '@next/swc-win32-arm64-msvc': 15.3.4
- '@next/swc-win32-x64-msvc': 15.3.4
+ '@next/swc-darwin-arm64': 15.3.5
+ '@next/swc-darwin-x64': 15.3.5
+ '@next/swc-linux-arm64-gnu': 15.3.5
+ '@next/swc-linux-arm64-musl': 15.3.5
+ '@next/swc-linux-x64-gnu': 15.3.5
+ '@next/swc-linux-x64-musl': 15.3.5
+ '@next/swc-win32-arm64-msvc': 15.3.5
+ '@next/swc-win32-x64-msvc': 15.3.5
sharp: 0.34.2
transitivePeerDependencies:
- '@babel/core'
diff --git a/middleware/public/favicon.ico b/middleware/public/favicon.ico
index 718d6fe..a6bb8d8 100644
--- a/middleware/public/favicon.ico
+++ b/middleware/public/favicon.ico
Binary files differ
diff --git a/middleware/src/app/[gameName]/page.tsx b/middleware/src/app/[gameName]/page.tsx
index ed5361a..a46b09d 100644
--- a/middleware/src/app/[gameName]/page.tsx
+++ b/middleware/src/app/[gameName]/page.tsx
@@ -355,6 +355,20 @@ function NewsPostPage({
: `${mainNewsUrl}/game/${gameName}#${postId}`
: null;
+ const createToggleUrl = () => {
+ const params = new URLSearchParams();
+ params.set('post', postId);
+
+ if (lang === 'en') {
+ } else {
+ params.set('lang', 'en');
+ }
+
+ const baseUrl = gameName === "news" ? "/news" : `/game/${gameName}`;
+ const queryString = params.toString();
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
+ };
+
return (
<main className="min-h-screen text-white font-sans bg-black">
<div className="w-full max-w-xl mx-auto px-3 sm:px-4 py-5 box-border">
@@ -477,11 +491,21 @@ function NewsPostPage({
{/* Navigation Buttons */}
<div className="mt-3 flex flex-col items-center gap-2.5 text-center">
+ {/* Language Toggle Button */}
+ {(newsPost.en_headline || newsPost.en_content) && (
+ <Link
+ href={createToggleUrl()}
+ className="block w-full max-w-xs bg-linear-to-br from-purple-500 to-purple-700 text-white px-5 py-3.5 rounded-md text-sm font-semibold shadow-md shadow-purple-500/30 no-underline border-0 transition-all duration-200 text-center hover:brightness-110 active:translate-y-px"
+ >
+ {lang === "en" ? "日本語で読む" : "Read in English"}
+ </Link>
+ )}
+
<Link
href="/"
- className="block w-full max-w-xs bg-gradient-to-br from-blue-500 to-blue-700 text-white px-5 py-3.5 rounded-md text-sm font-semibold shadow-md shadow-blue-500/30 no-underline border-0 transition-all duration-200 text-center hover:brightness-110 active:translate-y-px"
+ className="block w-full max-w-xs bg-linear-to-br from-blue-500 to-blue-700 text-white px-5 py-3.5 rounded-md text-sm font-semibold shadow-md shadow-blue-500/30 no-underline border-0 transition-all duration-200 text-center hover:brightness-110 active:translate-y-px"
>
- Back to 573 UPDATES
+ {lang === "en" ? "Back to 573 UPDATES" : "573 UPDATESに戻る"}
</Link>
</div>
</div>
diff --git a/news_feed.py b/news_feed.py
index cb76ba8..1bcb240 100644
--- a/news_feed.py
+++ b/news_feed.py
@@ -48,11 +48,11 @@ def _attach_llm_summaries(news_posts: list, game_name: str):
# BEMANI (Specific feeds because these provide better information)
# ---------------------------------------------------------------------------
-@registry.register(constants.SOUND_VOLTEX_EXCEED_GEAR_NEWS_SITE)
+@registry.register(constants.SOUND_VOLTEX_NABLA_NEWS_SITE)
class SoundVoltexSource(NewsSource):
def fetch(self, version=None) -> list[dict]:
from bemani.sdvx import parse_exceed_gear_news_site
- site_data = download_site_as_html(constants.SOUND_VOLTEX_EXCEED_GEAR_NEWS_SITE)
+ site_data = download_site_as_html(constants.SOUND_VOLTEX_NABLA_NEWS_SITE)
news_posts = sorted(parse_exceed_gear_news_site(site_data), key=lambda x: x['timestamp'], reverse=True)
return translate.add_translate_text_to_en(news_posts, overrides=[("ボルテ", "SDVX")])
diff --git a/site/src/pages/Homepage.tsx b/site/src/pages/Homepage.tsx
index 13ec4fd..24052d7 100644
--- a/site/src/pages/Homepage.tsx
+++ b/site/src/pages/Homepage.tsx
@@ -196,11 +196,11 @@ export default function Home() {
viewBox="-271 273 256 256"
xmlSpace="preserve"
>
- <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
+ <g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g
id="SVGRepo_tracerCarrier"
- stroke-linecap="round"
- stroke-linejoin="round"
+ strokeLinejoin="round"
+ strokeLinecap="round"
></g>
<g id="SVGRepo_iconCarrier">
{" "}
diff --git a/summarizer.py b/summarizer.py
index 0c30347..689626d 100644
--- a/summarizer.py
+++ b/summarizer.py
@@ -90,5 +90,5 @@ def generate_headline_and_content_from_images(img_urls: list[str], game: str, me
except openai.OpenAIError as e:
print(f"[ERROR] Function call to OpenAI for summarization failed ERROR -> {e} ")
database.close()
- return None, None
+ return f"NEW {game} INFORMATION / 新しい{game}情報", f"NEW {game} INFORMATION AVAILABLE / 新しい{game}情報が利用可能です"
return headline, content
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage