Skip to content

fix(nicojk): コメント取得が不安定な件の対策 - #35

Merged
ci7lus merged 7 commits into
mainfrom
fix/niconico-discontinue
Aug 29, 2026
Merged

ci7lus merged 7 commits into
mainfrom
fix/niconico-discontinue

Conversation

@ci7lus

@ci7lus ci7lus commented Aug 29, 2026 •

Copy link
Copy Markdown
Owner

WKWebViewからのmpnリクエストが時々詰まってしまうようで、原因がよくわかっていない。これの対策のために動作を公式に寄せてみたり、無音のメディアを流してみたり、タイムアウトを短くしたりした。結局あんまりよくならなかったので取得元のデフォルトをnx-jikkyoに戻した。

image

Sourceryによる概要

NicoNicoのライブコメント取得とレンダリングを安定化し、nx-jikkyoをデフォルトのソースに変更しました。

新機能:

  • リトライ、タイムアウト、重複排除、セグメントの独立処理に対応した、堅牢なNicoNicoライブコメント取得機能を追加。
  • オーバーレイレンダラーの再構築時に、カスタム表示時間が設定されたコメントを含め、表示中のライブコメントを保持。

バグ修正:

  • 停滞または古くなったNicoNicoの視聴接続が、アクティブなコメントストリームを中断しないように修正。
  • コメント到着時の不要なライブプレイヤー同期と、繰り返し行われるソートを回避。

改善:

  • ライブコメントの増分マージと、ターゲット状態の一括同期を最適化。
  • ライブコメントの取得元をデフォルトでnx-jikkyoに変更し、NicoNicoは明示的なオプションとして引き続き利用可能に。
  • パネル内の中断されたソースおよびチャプター補正コントロールのレイアウトを改善。

テスト:

  • NDGRのリトライ動作、ストリームの独立性、再接続、ソケットのライフサイクル、レンダラーのシード処理、ライブコメント取得元のデフォルト設定に関するテストカバレッジを追加。
Original summary in English

Sourceryによる概要

NicoNicoのライブコメントの取得とレンダリングを安定化し、デフォルトのソースをnx-jikkyoに変更しました。

新機能:

  • リトライ、タイムアウト、再接続処理、セグメント単位の独立した処理に対応した、堅牢なNicoNicoライブコメント取得機能を追加。
  • オーバーレイレンダラーの再構築時にも、現在表示中のライブコメントを保持。カスタム表示時間が設定されたコメントにも対応。

バグ修正:

  • 古い、または切断されたNicoNico視聴ソケットによって、アクティブなコメントストリームが中断される問題を防止。
  • 不要なプレーヤー同期を回避し、重複排除と順序の効率的な維持によってコメントのマージ処理を改善。

機能強化:

  • nx-jikkyoをデフォルトのライブコメントソースに変更し、NicoNicoは明示的なオプションとして引き続き利用可能にしました。
  • ソースが中断された場合のパネルレイアウトと、チャプター修正用コントロールを改善。

テスト:

  • NDGRのリトライ動作、ストリームの独立性、再接続、ソケットのライフサイクル、レンダラーへのコメント初期投入、デフォルトのコメントソースに関するテストカバレッジを拡充。
Original summary in English

Summary by Sourcery

Stabilize NicoNico live-comment retrieval and rendering while switching the default source to nx-jikkyo.

New Features:

  • Add resilient NicoNico live-comment retrieval with retries, timeouts, reconnect handling, and independent segment processing.
  • Preserve still-visible live comments when rebuilding the overlay renderer, including comments with custom display durations.

Bug Fixes:

  • Prevent stale or disconnected NicoNico watch sockets from interrupting active comment streams.
  • Avoid redundant player synchronization and improve comment merging by deduplicating and maintaining order efficiently.

Enhancements:

  • Make nx-jikkyo the default live-comment source while retaining NicoNico as an explicit option.
  • Improve the panel layout for interrupted sources and chapter-correction controls.

Tests:

  • Expand coverage for NDGR retry behavior, stream independence, reconnection, socket lifecycle, renderer seeding, and the default comment source.

@sourcery-ai

sourcery-ai Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

レビュアーガイド

この PR では、タイムアウトした NDGR の view/segment ストリームを分離して再試行し、古くなった watch-session URL を更新し、bootstrap WebSocket を独立してクローズすることで、NicoNico コメント取得の堅牢性を高めています。また、コメントのマージとライブレンダラーの再構築を最適化し、nx-jikkyo をデフォルトの取得元に戻し、関連する UI レイアウトを調整しています。

堅牢な NicoNico コメント取得のシーケンス図

sequenceDiagram
    participant Client as NiconicoCommentClient
    participant Watch as WatchPage
    participant WS as BootstrapWebSocket
    participant View as NDGRViewStream
    participant Segment as NDGRSegmentStream

    loop reconnect session
        Client->>Watch: resolveNiconicoWatchPage()
        Client->>WS: openWatchSocket()
        WS-->>Client: viewUri
        Client->>WS: close()
        Client->>View: consumeViewSegment()
        View-->>Client: segment URI
        Client->>Segment: startSegment()
        Segment-->>Client: comment messages
        alt timeout or stream failure
            Client->>Segment: retry with runNdgrWithRetry()
            Client->>View: retry with runNdgrWithRetry()
        end
    end
Loading

ライブコメント取得元選択の状態図

stateDiagram-v2
    [*] --> NxJikkyoDefault
    NxJikkyoDefault --> Niconico: user selects niconico
    Niconico --> NxJikkyoDefault: user selects nx-jikkyo
    NxJikkyoDefault --> NxJikkyoDefault: invalid or missing setting
Loading

効率的なライブコメント更新のフロー図

flowchart TD
    A[Incoming live comment] --> B{One new comment?}
    B -- Yes --> C{Duplicate ID?}
    C -- Yes --> D[Keep existing comments]
    C -- No --> E[Binary-search sorted position]
    E --> F[Insert comment and trim maxCount]
    B -- No --> G[Sort and deduplicate merged comments]
    F --> H[Schedule target sync]
    G --> H
    H --> I[Batch player IDs for 50 ms]
    I --> J["syncTargetState()"]
Loading

ファイル単位の変更

変更内容 詳細 ファイル
停滞、失敗、または古くなった接続に対して、NicoNico NDGR コメント取得を堅牢化。
  • ジッターを伴う設定可能な指数バックオフ再試行と、ヘッダー取得/ストリーム読み取り用の個別タイムアウトを追加。
  • タイムアウトした試行を親セッションを終了させずに中断し、view リクエストと segment リクエストを個別に再試行。
  • 再接続時に最新の watch ページを取得し、View URI の取得後に WebSocket をクローズし、segment タスクを重複排除しながら並行して追跡。
  • 再試行、タイムアウトからの復旧、ストリームの独立性、ソケットのライフサイクル、abort 動作のテストカバレッジを追加。
src/plugins/nicojk/niconico-comment-client.ts
tests/nicojk-niconico-comment-client.test.ts
コメントを保持しつつ、ライブコメント処理とレンダラー再構築のオーバーヘッドを削減。
  • 単一の受信コメントをコレクション全体のソートではなく、二分探索を使ってソート済みの保持リストに挿入。
  • ライブのターゲット状態同期を 50 ms の間隔でまとめて実行し、破棄時にタイマーをクリーンアップ。
  • 現在位置まで表示時間と描画リードが継続するコメントのみを使ってライブレンダラーを再構築。カスタムの @ duration コマンドも対象。
  • レンダラーの初期シード処理に関するテストを追加。
src/plugins/nicojk/App.tsx
src/plugins/nicojk/components/OverlayPage.tsx
tests/nicojk-overlay-page.test.ts
nx-jikkyo をデフォルトのライブコメント取得元に戻す。
  • 明示的に niconico が指定された場合のみ代替取得元として扱い、不明な値または未設定の値は nx-jikkyo に正規化。
  • デフォルト取得元のテストを更新。
src/plugins/nicojk/ng-settings.ts
tests/nicojk-settings.test.ts
中断された取得元およびチャプター補正パネルのレイアウトを改善。
  • チャプター補正コントロールの配置を維持し、長いラベルの折り返しを許可。
  • 再開コントロールは中断された取得元に対してのみ表示し、中断されたチャンクの進捗インジケーターは維持。
src/plugins/nicojk/components/PanelPage.tsx

関連する可能性のある Issue

  • #: PR ではニコ生コメント取得機能の安定化と再試行、および取得元設定の変更を行っています。

ヒントとコマンド

Sourcery の操作

  • 新しいレビューを実行: プルリクエストに @sourcery-ai review とコメントします。
  • ディスカッションを続ける: Sourcery のレビューコメントに直接返信します。
  • レビューコメントから GitHub Issue を作成: レビューコメントに返信して、Sourcery に Issue の作成を依頼します。レビューコメントに @sourcery-ai issue と返信して Issue を作成することもできます。
  • プルリクエストのタイトルを生成: プルリクエストのタイトル内の任意の場所に @sourcery-ai と記述すると、いつでもタイトルを生成できます。プルリクエストに @sourcery-ai title とコメントして、タイトルを再生成することもできます。
  • プルリクエストの概要を生成: プルリクエスト本文内の任意の場所に @sourcery-ai summary と記述すると、指定した位置に PR の概要をいつでも生成できます。プルリクエストに @sourcery-ai summary とコメントして、概要を再生成することもできます。
  • レビュアーガイドを生成: プルリクエストに @sourcery-ai guide とコメントすると、レビュアーガイドをいつでも再生成できます。
  • Sourcery のコメントをすべて解決: プルリクエストに @sourcery-ai resolve とコメントすると、Sourcery のコメントをすべて解決できます。すべてのコメントに対応済みで、これ以上表示したくない場合に便利です。
  • Sourcery のレビューをすべて却下: プルリクエストに @sourcery-ai dismiss とコメントすると、既存の Sourcery レビューをすべて却下できます。新しいレビューを最初からやり直したい場合に特に便利です。新しいレビューを実行するには、@sourcery-ai review とコメントすることを忘れないでください。

エクスペリエンスのカスタマイズ

ダッシュボード にアクセスして、次の操作を行えます。

  • Sourcery が生成するプルリクエスト概要、レビュアーガイドなどのレビュー機能を有効化または無効化する。
  • レビュー言語を変更する。
  • カスタムレビュー指示を追加、削除、編集する。
  • その他のレビュー設定を調整する。

ヘルプの利用

Original review guide in English

Reviewer's Guide

The PR hardens NicoNico comment retrieval by separating and retrying timed-out NDGR view/segment streams, refreshing stale watch-session URLs, and closing the bootstrap WebSocket independently; it also optimizes comment merging and live-renderer rebuilds, restores nx-jikkyo as the default source, and adjusts related UI layout.

Sequence diagram for resilient NicoNico comment retrieval

sequenceDiagram
    participant Client as NiconicoCommentClient
    participant Watch as WatchPage
    participant WS as BootstrapWebSocket
    participant View as NDGRViewStream
    participant Segment as NDGRSegmentStream

    loop reconnect session
        Client->>Watch: resolveNiconicoWatchPage()
        Client->>WS: openWatchSocket()
        WS-->>Client: viewUri
        Client->>WS: close()
        Client->>View: consumeViewSegment()
        View-->>Client: segment URI
        Client->>Segment: startSegment()
        Segment-->>Client: comment messages
        alt timeout or stream failure
            Client->>Segment: retry with runNdgrWithRetry()
            Client->>View: retry with runNdgrWithRetry()
        end
    end
Loading

State diagram for live comment source selection

stateDiagram-v2
    [*] --> NxJikkyoDefault
    NxJikkyoDefault --> Niconico: user selects niconico
    Niconico --> NxJikkyoDefault: user selects nx-jikkyo
    NxJikkyoDefault --> NxJikkyoDefault: invalid or missing setting
Loading

Flow diagram for efficient live comment updates

flowchart TD
    A[Incoming live comment] --> B{One new comment?}
    B -- Yes --> C{Duplicate ID?}
    C -- Yes --> D[Keep existing comments]
    C -- No --> E[Binary-search sorted position]
    E --> F[Insert comment and trim maxCount]
    B -- No --> G[Sort and deduplicate merged comments]
    F --> H[Schedule target sync]
    G --> H
    H --> I[Batch player IDs for 50 ms]
    I --> J["syncTargetState()"]
Loading

File-Level Changes

Change Details Files
Make NicoNico NDGR comment acquisition resilient to stalled, failed, or stale connections.
  • Added configurable exponential retry with jitter and separate fetch-header/stream-read timeouts.
  • Abort timed-out attempts without terminating the parent session, and retry view and segment requests independently.
  • Fetch a fresh watch page on reconnect, close the WebSocket after obtaining the View URI, and deduplicate/concurrently track segment tasks.
  • Added coverage for retries, timeout recovery, stream independence, socket lifecycle, and abort behavior.
src/plugins/nicojk/niconico-comment-client.ts
tests/nicojk-niconico-comment-client.test.ts
Reduce live-comment processing and renderer rebuild overhead while preserving comments that may still be visible.
  • Insert single incoming comments into the sorted retained list using binary search instead of sorting the full collection.
  • Batch live target-state synchronization within a 50 ms window and clean up the timer on teardown.
  • Seed live renderer rebuilds only with comments whose duration and draw lead extend to the current position, including custom @ duration commands.
  • Added renderer-seeding tests.
src/plugins/nicojk/App.tsx
src/plugins/nicojk/components/OverlayPage.tsx
tests/nicojk-overlay-page.test.ts
Restore nx-jikkyo as the default live-comment source.
  • Treat only an explicit niconico value as the alternate source and normalize unknown or missing values to nx-jikkyo.
  • Updated default-source tests.
src/plugins/nicojk/ng-settings.ts
tests/nicojk-settings.test.ts
Refine the interrupted-source and chapter-correction panel layout.
  • Keep chapter-correction controls aligned and allow long labels to wrap.
  • Show resume controls only for interrupted sources while retaining interrupted chunk progress indicators.
src/plugins/nicojk/components/PanelPage.tsx

Possibly linked issues

  • #: PRはニコ生コメント取得機能の安定化と再試行、取得元設定を変更している。

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こんにちは—1件の問題を見つけました

AIエージェント向けプロンプト
このコードレビューのコメントに対応してください。

## 個別のコメント

### コメント1
<location path="src/plugins/nicojk/niconico-comment-client.ts" line_range="616-625" />
<code_context>
+		const active = this.activeSegmentTasks.get(segmentUri);
+		if (active?.generation === generation) return;
+		if (active) this.activeSegmentTasks.delete(segmentUri);
+		if (this.seenSegmentUris.has(segmentUri)) return;
		this.seenSegmentUris.add(segmentUri);
+
+		let task: Promise<void>;
+		task = this.consumeSegment(segmentUri, vposBaseTime, signal, generation)
</code_context>
<issue_to_address>
**issue (bug_risk):** セグメントのURIが、取得に成功する前に `seenSegmentUris` に追加され、すべての再試行が失敗した場合にも削除されません。後でビューストリームが同じURIを再度通知すると、`startSegment` は取得せずに終了するため、そのセグメントのコメントが現在のセッション中ずっと失われます。

**Triggers:** セグメントの取得が `maxNumberOfRetry` 回の再試行を経ても失敗し続け、後のビュー応答で同じセグメントURIが再度通知された場合。

**Suggested fix:** セグメントタスクが再試行を使い果たした時点で、より新しいタスクがすでにそのURIを取得していない場合に限り、`seenSegmentUris` からURIを削除してください。

```suggestion
			.catch((error) => {
				if (this.activeSegmentTasks.get(segmentUri)?.task === task) {
					this.seenSegmentUris.delete(segmentUri);
				}
				if (!this.isIntentionalFailure(error, signal, generation)) {
					console.error("[NicoJK] NicoNico comment segment failed", error);
				}
			})
			.finally(() => {
				if (this.activeSegmentTasks.get(segmentUri)?.task === task) {
					this.activeSegmentTasks.delete(segmentUri);
				}
			});
```
</issue_to_address>

Sourceryによる評価

人間によるレビューが必要です。 先に対応すべき指摘が1件あり、明示的な設定がないユーザーに対するデフォルトのライブコメントソースを変更するとともに、ストリーミングクライアントの再試行、タイムアウト、再接続の動作を大幅に書き換えています。新しいソースや接続ポリシーに問題がある場合、ユーザーは直ちに欠落した、または誤ったコメントを受け取る可能性があります。また、デフォルトの決定は該当するすべてのユーザーに影響します。元に戻すことで新しい動作は停止できますが、ユーザーが保存した可能性のある設定が自動的に取り消されるわけではありません。

ブロッキングとなる指摘: src/plugins/nicojk/niconico-comment-client.ts:625


Sourceryはオープンソース向けに無料です—レビューを気に入っていただけた場合は、共有をご検討ください ✨
もっと役立つレビューにご協力ください!各コメントの 👍 または 👎 をクリックしていただければ、そのフィードバックをレビューの改善に活用します。
Original comment in English

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/plugins/nicojk/niconico-comment-client.ts" line_range="616-625" />
<code_context>
+		const active = this.activeSegmentTasks.get(segmentUri);
+		if (active?.generation === generation) return;
+		if (active) this.activeSegmentTasks.delete(segmentUri);
+		if (this.seenSegmentUris.has(segmentUri)) return;
+		this.seenSegmentUris.add(segmentUri);
+
+		let task: Promise<void>;
+		task = this.consumeSegment(segmentUri, vposBaseTime, signal, generation)
</code_context>
<issue_to_address>
**issue (bug_risk):** A segment URI is added to `seenSegmentUris` before its fetch succeeds and is never removed when all retries fail. If the view stream announces that URI again later, `startSegment` returns without fetching it, so comments from that segment are permanently lost for the current session.

**Triggers:** When a segment fetch continues to fail through `maxNumberOfRetry` and the same segment URI is announced again by a later view response.

**Suggested fix:** Remove the URI from `seenSegmentUris` when the segment task exhausts its retries, unless a newer task has already claimed it.

```suggestion
			.catch((error) => {
				if (this.activeSegmentTasks.get(segmentUri)?.task === task) {
					this.seenSegmentUris.delete(segmentUri);
				}
				if (!this.isIntentionalFailure(error, signal, generation)) {
					console.error("[NicoJK] NicoNico comment segment failed", error);
				}
			})
			.finally(() => {
				if (this.activeSegmentTasks.get(segmentUri)?.task === task) {
					this.activeSegmentTasks.delete(segmentUri);
				}
			});
```
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and this changes the default live-comment source for users without an explicit setting and substantially rewrites the streaming client’s retry, timeout, and reconnection behavior. If the new source or connection policy is wrong, users can immediately receive missing or incorrect comments and the default decision affects every such user; reverting stops the new behavior but does not automatically undo any persisted settings users may have adopted.

Blocking findings: src/plugins/nicojk/niconico-comment-client.ts:625


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/plugins/nicojk/niconico-comment-client.ts
@ci7lus
ci7lus merged commit dc93af8 into main Aug 29, 2026
3 checks passed
@ci7lus
ci7lus deleted the fix/niconico-discontinue branch August 29, 2026 07:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant