Files
rl-mobile/patches/extension/radiant/WordLyrics.smali
T
2026-07-18 15:02:07 +10:00

1124 lines
25 KiB
Smali

.class public final Lradiant/WordLyrics;
.super Ljava/lang/Object;
# Word-level lyrics highlighting support for the RL-API lyrics injection.
# Parses the API "Word" payload (per-line syllabus[]) into per-line word arrays,
# runs a 50ms main-thread clock that publishes an interpolated playhead into a Compose
# MutableState, and builds a two-tone AnnotatedString (sung / unsung) that the patched
# PlayerScreen line composable (f2) renders for whatever line Compose marks active.
# Line-level data (scroll, line index) still comes from TIDAL's own g$c pipeline.
#
# ROBUSTNESS: render() gates on Compose's OWN active-line index (f2.b) — not a clock
# guess — and the active line ALWAYS reads the playhead state, so it can never lose its
# recomposition subscription and get stranded on line-highlighting.
# static state
.field public static lineStarts:[J
.field public static lineWordText:[[Ljava/lang/String;
.field public static lineWordStart:[[J
.field public static volatile playheadState:Landroidx/compose/runtime/MutableState;
# active RL line index (from clock over lineStarts)
.field public static volatile activeLineState:Landroidx/compose/runtime/MutableState;
.field public static volatile baseMs:J
.field public static volatile baseAnchor:J
.field public static volatile ticking:Z
# per-render scratch handed to styleSpot
.field public static tmpStarts:[J
.field public static tmpOffs:[I
.field public static tmpN:I
.field public static tmpNow:J
.field public static tmpSung:J
.field public static tmpUnsung:J
.field public static handler:Landroid/os/Handler;
.field public static tickRunnable:Ljava/lang/Runnable;
.field public static sungColor:J
.field public static sungSpan:Landroidx/compose/ui/text/SpanStyle;
.field public static unsungColor:J
.field public static unsungSpan:Landroidx/compose/ui/text/SpanStyle;
.method private constructor <init>()V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# snapshot state (interpolated playhead ms)
.method public static state()Landroidx/compose/runtime/MutableState;
.locals 2
sget-object v0, Lradiant/WordLyrics;->playheadState:Landroidx/compose/runtime/MutableState;
if-nez v0, :ret
const/4 v0, 0x0
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v0
invoke-static {}, Landroidx/compose/runtime/SnapshotStateKt;->structuralEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
move-result-object v1
invoke-static {v0, v1}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)Landroidx/compose/runtime/MutableState;
move-result-object v0
sput-object v0, Lradiant/WordLyrics;->playheadState:Landroidx/compose/runtime/MutableState;
:ret
return-object v0
.end method
# active-line snapshot state (init -1)
.method public static lineState()Landroidx/compose/runtime/MutableState;
.locals 2
sget-object v0, Lradiant/WordLyrics;->activeLineState:Landroidx/compose/runtime/MutableState;
if-nez v0, :ret
const/4 v0, -0x1
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v0
invoke-static {}, Landroidx/compose/runtime/SnapshotStateKt;->structuralEqualityPolicy()Landroidx/compose/runtime/SnapshotMutationPolicy;
move-result-object v1
invoke-static {v0, v1}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;)Landroidx/compose/runtime/MutableState;
move-result-object v0
sput-object v0, Lradiant/WordLyrics;->activeLineState:Landroidx/compose/runtime/MutableState;
:ret
return-object v0
.end method
.method public static setData([J[[Ljava/lang/String;[[J)V
.locals 0
sput-object p0, Lradiant/WordLyrics;->lineStarts:[J
sput-object p1, Lradiant/WordLyrics;->lineWordText:[[Ljava/lang/String;
sput-object p2, Lradiant/WordLyrics;->lineWordStart:[[J
invoke-static {}, Lradiant/WordLyrics;->state()Landroidx/compose/runtime/MutableState;
invoke-static {}, Lradiant/WordLyrics;->lineState()Landroidx/compose/runtime/MutableState;
invoke-static {}, Lradiant/WordLyrics;->startClock()V
return-void
.end method
.method public static clear()V
.locals 1
const/4 v0, 0x0
sput-object v0, Lradiant/WordLyrics;->lineStarts:[J
sput-object v0, Lradiant/WordLyrics;->lineWordText:[[Ljava/lang/String;
sput-object v0, Lradiant/WordLyrics;->lineWordStart:[[J
invoke-static {}, Lradiant/WordLyrics;->stopClock()V
return-void
.end method
.method public static onProgress(J)V
.locals 4
sput-wide p0, Lradiant/WordLyrics;->baseMs:J
invoke-static {}, Landroid/os/SystemClock;->elapsedRealtime()J
move-result-wide v0
sput-wide v0, Lradiant/WordLyrics;->baseAnchor:J
# self-heal: restart the clock if data is present but it stopped
sget-object v2, Lradiant/WordLyrics;->lineWordText:[[Ljava/lang/String;
if-eqz v2, :done_op
sget-boolean v2, Lradiant/WordLyrics;->ticking:Z
if-nez v2, :done_op
invoke-static {}, Lradiant/WordLyrics;->startClock()V
:done_op
return-void
.end method
# Clock
.method public static startClock()V
.locals 2
sget-boolean v0, Lradiant/WordLyrics;->ticking:Z
if-nez v0, :done
const/4 v0, 0x1
sput-boolean v0, Lradiant/WordLyrics;->ticking:Z
sget-object v0, Lradiant/WordLyrics;->handler:Landroid/os/Handler;
if-nez v0, :have_h
new-instance v0, Landroid/os/Handler;
invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
move-result-object v1
invoke-direct {v0, v1}, Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
sput-object v0, Lradiant/WordLyrics;->handler:Landroid/os/Handler;
:have_h
sget-object v0, Lradiant/WordLyrics;->tickRunnable:Ljava/lang/Runnable;
if-nez v0, :have_r
new-instance v0, Lradiant/WordLyricsTick;
invoke-direct {v0}, Lradiant/WordLyricsTick;-><init>()V
sput-object v0, Lradiant/WordLyrics;->tickRunnable:Ljava/lang/Runnable;
:have_r
sget-object v0, Lradiant/WordLyrics;->handler:Landroid/os/Handler;
sget-object v1, Lradiant/WordLyrics;->tickRunnable:Ljava/lang/Runnable;
invoke-virtual {v0, v1}, Landroid/os/Handler;->post(Ljava/lang/Runnable;)Z
:done
return-void
.end method
.method public static stopClock()V
.locals 2
const/4 v0, 0x0
sput-boolean v0, Lradiant/WordLyrics;->ticking:Z
sget-object v0, Lradiant/WordLyrics;->handler:Landroid/os/Handler;
if-eqz v0, :ret
sget-object v1, Lradiant/WordLyrics;->tickRunnable:Ljava/lang/Runnable;
if-eqz v1, :ret
invoke-virtual {v0, v1}, Landroid/os/Handler;->removeCallbacks(Ljava/lang/Runnable;)V
:ret
return-void
.end method
.method static computeNow()J
.locals 7
sget-wide v0, Lradiant/WordLyrics;->baseMs:J
sget-wide v2, Lradiant/WordLyrics;->baseAnchor:J
invoke-static {}, Landroid/os/SystemClock;->elapsedRealtime()J
move-result-wide v4
sub-long/2addr v4, v2
const-wide/16 v2, 0x0
cmp-long v6, v4, v2
if-gez v6, :chk_hi
move-wide v4, v2
goto :add
:chk_hi
const-wide/16 v2, 0x190
cmp-long v6, v4, v2
if-lez v6, :add
move-wide v4, v2
:add
add-long/2addr v0, v4
return-wide v0
.end method
# largest index i with arr[i] <= v, else -1 (arr ascending)
.method static search([JJ)I
.locals 5
const/4 v0, -0x1
if-eqz p0, :done
array-length v1, p0
const/4 v2, 0x0
:loop
if-ge v2, v1, :done
aget-wide v3, p0, v2
cmp-long v4, v3, p1
if-gtz v4, :done
move v0, v2
add-int/lit8 v2, v2, 0x1
goto :loop
:done
return v0
.end method
# 33ms tick: publish the interpolated playhead + the active RL line into snapshot states
.method public static tick()V
.locals 6
sget-object v0, Lradiant/WordLyrics;->lineWordText:[[Ljava/lang/String;
if-eqz v0, :stop
invoke-static {}, Lradiant/WordLyrics;->computeNow()J
move-result-wide v0
# active RL line index (search over lineStarts)
sget-object v2, Lradiant/WordLyrics;->lineStarts:[J
invoke-static {v2, v0, v1}, Lradiant/WordLyrics;->search([JJ)I
move-result v2
invoke-static {}, Lradiant/WordLyrics;->lineState()Landroidx/compose/runtime/MutableState;
move-result-object v3
invoke-interface {v3}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object;
move-result-object v4
if-eqz v4, :set_al
check-cast v4, Ljava/lang/Integer;
invoke-virtual {v4}, Ljava/lang/Integer;->intValue()I
move-result v5
if-eq v5, v2, :al_done
:set_al
invoke-static {v2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v4
invoke-interface {v3, v4}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V
:al_done
# playhead tick (every frame) -> playheadState (drives active line fade)
long-to-int v0, v0
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v0
invoke-static {}, Lradiant/WordLyrics;->state()Landroidx/compose/runtime/MutableState;
move-result-object v1
invoke-interface {v1, v0}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V
sget-boolean v0, Lradiant/WordLyrics;->ticking:Z
if-eqz v0, :done
sget-object v0, Lradiant/WordLyrics;->handler:Landroid/os/Handler;
if-eqz v0, :done
sget-object v1, Lradiant/WordLyrics;->tickRunnable:Ljava/lang/Runnable;
if-eqz v1, :done
const-wide/16 v2, 0x21
invoke-virtual {v0, v1, v2, v3}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z
:done
return-void
:stop
const/4 v0, 0x0
sput-boolean v0, Lradiant/WordLyrics;->ticking:Z
return-void
.end method
# render
.method public static render(IILjava/lang/String;JJ)Landroidx/compose/ui/text/AnnotatedString;
.locals 18
move/from16 v15, p0
move-object/from16 v10, p2
move-wide/from16 v11, p3
move-wide/from16 v13, p5
# only style lines that have RL word data
sget-boolean v0, Lradiant/RLAPILyricsHook;->isRlState:Z
if-eqz v0, :plain
sget-object v0, Lradiant/WordLyrics;->lineWordText:[[Ljava/lang/String;
if-eqz v0, :plain
if-ltz v15, :plain
array-length v1, v0
if-ge v15, v1, :plain
aget-object v1, v0, v15
if-eqz v1, :plain
array-length v2, v1
if-eqz v2, :plain
sget-object v3, Lradiant/WordLyrics;->lineWordStart:[[J
if-eqz v3, :plain
aget-object v3, v3, v15
if-eqz v3, :plain
# build line text + per word char offsets (offsets[n] = total length)
new-instance v6, Landroidx/compose/ui/text/AnnotatedString$Builder;
invoke-direct {v6}, Landroidx/compose/ui/text/AnnotatedString$Builder;-><init>()V
add-int/lit8 v8, v2, 0x1
new-array v7, v8, [I
const/4 v8, 0x0
const/4 v9, 0x0
:aloop
if-ge v8, v2, :adone
aput v9, v7, v8
aget-object v0, v1, v8
invoke-virtual {v6, v0}, Landroidx/compose/ui/text/AnnotatedString$Builder;->append(Ljava/lang/String;)V
invoke-virtual {v0}, Ljava/lang/String;->length()I
move-result v0
add-int/2addr v9, v0
add-int/lit8 v8, v8, 0x1
goto :aloop
:adone
aput v9, v7, v2
# base grey span over the whole line (stops flicker)
const/4 v0, 0x0
invoke-static {v13, v14, v0}, Lradiant/WordLyrics;->span(JZ)Landroidx/compose/ui/text/SpanStyle;
move-result-object v0
const/4 v8, 0x0
invoke-virtual {v6, v0, v8, v9}, Landroidx/compose/ui/text/AnnotatedString$Builder;->addStyle(Landroidx/compose/ui/text/SpanStyle;II)V
# active line = clocks line
invoke-static {}, Lradiant/WordLyrics;->lineState()Landroidx/compose/runtime/MutableState;
move-result-object v0
invoke-interface {v0}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object;
move-result-object v0
const/4 v4, -0x1
if-eqz v0, :have_al
check-cast v0, Ljava/lang/Integer;
invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
move-result v4
:have_al
if-ne v15, v4, :emit
# active line subscribes to the playhead tick (fade) & create/use a fresh playhead
invoke-static {}, Lradiant/WordLyrics;->state()Landroidx/compose/runtime/MutableState;
move-result-object v0
invoke-interface {v0}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object;
invoke-static {}, Lradiant/WordLyrics;->computeNow()J
move-result-wide v4
invoke-static {v3, v4, v5}, Lradiant/WordLyrics;->search([JJ)I
move-result v8
if-ltz v8, :emit
# spotlight (only the active word is highlighted)
sput-object v3, Lradiant/WordLyrics;->tmpStarts:[J
sput-object v7, Lradiant/WordLyrics;->tmpOffs:[I
sput v2, Lradiant/WordLyrics;->tmpN:I
sput-wide v4, Lradiant/WordLyrics;->tmpNow:J
sput-wide v11, Lradiant/WordLyrics;->tmpSung:J
sput-wide v13, Lradiant/WordLyrics;->tmpUnsung:J
invoke-static {v6, v8}, Lradiant/WordLyrics;->styleSpot(Landroidx/compose/ui/text/AnnotatedString$Builder;I)V
:emit
invoke-virtual {v6}, Landroidx/compose/ui/text/AnnotatedString$Builder;->toAnnotatedString()Landroidx/compose/ui/text/AnnotatedString;
move-result-object v0
return-object v0
:plain
new-instance v0, Landroidx/compose/ui/text/AnnotatedString$Builder;
invoke-direct {v0, v10}, Landroidx/compose/ui/text/AnnotatedString$Builder;-><init>(Ljava/lang/String;)V
invoke-virtual {v0}, Landroidx/compose/ui/text/AnnotatedString$Builder;->toAnnotatedString()Landroidx/compose/ui/text/AnnotatedString;
move-result-object v0
return-object v0
.end method
# Colour the single active word j (faded grey<->white by its bump curve)
.method static styleSpot(Landroidx/compose/ui/text/AnnotatedString$Builder;I)V
.locals 12
sget v0, Lradiant/WordLyrics;->tmpN:I
if-ltz p1, :done
if-ge p1, v0, :done
sget-object v1, Lradiant/WordLyrics;->tmpStarts:[J
aget-wide v2, v1, p1
add-int/lit8 v4, p1, 0x1
if-ge v4, v0, :last_w
aget-wide v4, v1, v4
goto :have_we
:last_w
const-wide/16 v4, 0x320
add-long/2addr v4, v2
:have_we
sget-wide v6, Lradiant/WordLyrics;->tmpNow:J
invoke-static/range {v2 .. v7}, Lradiant/WordLyrics;->bump(JJJ)F
move-result v8
const v9, 0x3c23d70a
cmpg-float v10, v8, v9
if-lez v10, :done
sget-wide v0, Lradiant/WordLyrics;->tmpUnsung:J
sget-wide v2, Lradiant/WordLyrics;->tmpSung:J
invoke-static {v0, v1, v2, v3, v8}, Landroidx/compose/ui/graphics/ColorKt;->lerp-jxsXWHM(JJF)J
move-result-wide v0
invoke-static {v0, v1}, Lradiant/WordLyrics;->makeSpan(J)Landroidx/compose/ui/text/SpanStyle;
move-result-object v0
sget-object v1, Lradiant/WordLyrics;->tmpOffs:[I
aget v2, v1, p1
add-int/lit8 v3, p1, 0x1
aget v3, v1, v3
invoke-virtual {p0, v0, v2, v3}, Landroidx/compose/ui/text/AnnotatedString$Builder;->addStyle(Landroidx/compose/ui/text/SpanStyle;II)V
:done
return-void
.end method
# Fade Curve (tech blabble below)
# Fade curve for a word active over [ws, we) ramps 0 -> 1 over the first FADE ms & 1 -> 0 over the last FADE ms (min of the two ramps) 0 outside the window
.method static bump(JJJ)F
.locals 6
cmp-long v0, p4, p0
if-ltz v0, :zero
cmp-long v0, p4, p2
if-gez v0, :zero
sub-long v0, p4, p0
long-to-float v0, v0
const v1, 0x42f00000
div-float v0, v0, v1
sub-long v2, p2, p4
long-to-float v2, v2
div-float v2, v2, v1
cmpg-float v3, v0, v2
if-lez v3, :have_min
move v0, v2
:have_min
const v1, 0x3f800000
cmpg-float v3, v0, v1
if-lez v3, :ret
move v0, v1
:ret
return v0
:zero
const/4 v0, 0x0
return v0
.end method
# cached SpanStyle per color (p2=isSung slot)
.method static span(JZ)Landroidx/compose/ui/text/SpanStyle;
.locals 3
if-eqz p2, :unsung
sget-object v0, Lradiant/WordLyrics;->sungSpan:Landroidx/compose/ui/text/SpanStyle;
if-eqz v0, :build_s
sget-wide v1, Lradiant/WordLyrics;->sungColor:J
cmp-long v2, v1, p0
if-nez v2, :build_s
return-object v0
:build_s
invoke-static {p0, p1}, Lradiant/WordLyrics;->makeSpan(J)Landroidx/compose/ui/text/SpanStyle;
move-result-object v0
sput-object v0, Lradiant/WordLyrics;->sungSpan:Landroidx/compose/ui/text/SpanStyle;
sput-wide p0, Lradiant/WordLyrics;->sungColor:J
return-object v0
:unsung
sget-object v0, Lradiant/WordLyrics;->unsungSpan:Landroidx/compose/ui/text/SpanStyle;
if-eqz v0, :build_u
sget-wide v1, Lradiant/WordLyrics;->unsungColor:J
cmp-long v2, v1, p0
if-nez v2, :build_u
return-object v0
:build_u
invoke-static {p0, p1}, Lradiant/WordLyrics;->makeSpan(J)Landroidx/compose/ui/text/SpanStyle;
move-result-object v0
sput-object v0, Lradiant/WordLyrics;->unsungSpan:Landroidx/compose/ui/text/SpanStyle;
sput-wide p0, Lradiant/WordLyrics;->unsungColor:J
return-object v0
.end method
# SpanStyle(color = <p0>) with every other property defaulted (mask 0xFFFE, bit0 clear = provide color)
.method static makeSpan(J)Landroidx/compose/ui/text/SpanStyle;
.locals 23
new-instance v0, Landroidx/compose/ui/text/SpanStyle;
move-wide/from16 v1, p0
const-wide/16 v3, 0x0
const/4 v5, 0x0
const/4 v6, 0x0
const/4 v7, 0x0
const/4 v8, 0x0
const/4 v9, 0x0
const-wide/16 v10, 0x0
const/4 v12, 0x0
const/4 v13, 0x0
const/4 v14, 0x0
const-wide/16 v15, 0x0
const/16 v17, 0x0
const/16 v18, 0x0
const/16 v19, 0x0
const/16 v20, 0x0
const v21, 0xfffe
const/16 v22, 0x0
invoke-direct/range {v0 .. v22}, Landroidx/compose/ui/text/SpanStyle;-><init>(JJLandroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontSynthesis;Landroidx/compose/ui/text/font/FontFamily;Ljava/lang/String;JLandroidx/compose/ui/text/style/BaselineShift;Landroidx/compose/ui/text/style/TextGeometricTransform;Landroidx/compose/ui/text/intl/LocaleList;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/graphics/Shadow;Landroidx/compose/ui/text/PlatformSpanStyle;Landroidx/compose/ui/graphics/drawscope/DrawStyle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
return-object v0
.end method
# ingest API ("Word" payload into per line word arrays)
.method public static ingest(Ljava/lang/String;)V
.locals 20
:try_start
move-object/from16 v9, p0
new-instance v6, Lorg/json/JSONObject;
invoke-direct {v6, v9}, Lorg/json/JSONObject;-><init>(Ljava/lang/String;)V
const-string v7, "type"
const-string v8, ""
invoke-virtual {v6, v7, v8}, Lorg/json/JSONObject;->optString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v7
const-string v8, "Word"
invoke-virtual {v8, v7}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v7
if-nez v7, :is_word
const-string v7, "WordLyrics ingest: not Word type -> cleared"
invoke-static {v7}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
invoke-static {}, Lradiant/WordLyrics;->clear()V
return-void
:is_word
const-string v7, "data"
invoke-virtual {v6, v7}, Lorg/json/JSONObject;->optJSONArray(Ljava/lang/String;)Lorg/json/JSONArray;
move-result-object v0
if-nez v0, :have_data
invoke-static {}, Lradiant/WordLyrics;->clear()V
return-void
:have_data
invoke-virtual {v0}, Lorg/json/JSONArray;->length()I
move-result v1
if-nez v1, :nonempty
invoke-static {}, Lradiant/WordLyrics;->clear()V
return-void
:nonempty
new-array v2, v1, [J
new-array v3, v1, [[Ljava/lang/String;
new-array v4, v1, [[J
const/4 v5, 0x0
:line_loop
if-ge v5, v1, :lines_done
invoke-virtual {v0, v5}, Lorg/json/JSONArray;->getJSONObject(I)Lorg/json/JSONObject;
move-result-object v6
const-string v7, "startTime"
const-wide/16 v8, 0x0
invoke-virtual {v6, v7, v8, v9}, Lorg/json/JSONObject;->optDouble(Ljava/lang/String;D)D
move-result-wide v7
const-wide v9, 0x408f400000000000L
mul-double/2addr v7, v9
double-to-long v7, v7
aput-wide v7, v2, v5
const-string v7, "syllabus"
invoke-virtual {v6, v7}, Lorg/json/JSONObject;->optJSONArray(Ljava/lang/String;)Lorg/json/JSONArray;
move-result-object v7
if-eqz v7, :single
invoke-virtual {v7}, Lorg/json/JSONArray;->length()I
move-result v8
if-nez v8, :have_syl
:single
const/4 v8, 0x1
new-array v9, v8, [Ljava/lang/String;
const-string v10, "text"
const-string v11, ""
invoke-virtual {v6, v10, v11}, Lorg/json/JSONObject;->optString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v10
const/4 v11, 0x0
aput-object v10, v9, v11
aput-object v9, v3, v5
new-array v9, v8, [J
aget-wide v7, v2, v5
aput-wide v7, v9, v11
aput-object v9, v4, v5
goto :line_next
:have_syl
const/4 v9, 0x0
const/4 v10, 0x0
:count_loop
if-ge v10, v8, :count_done
invoke-virtual {v7, v10}, Lorg/json/JSONArray;->getJSONObject(I)Lorg/json/JSONObject;
move-result-object v11
const-string v12, "text"
const-string v13, ""
invoke-virtual {v11, v12, v13}, Lorg/json/JSONObject;->optString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v11
invoke-static {v11, v10, v8}, Lradiant/WordLyrics;->isWordEnd(Ljava/lang/String;II)Z
move-result v11
if-eqz v11, :count_next
add-int/lit8 v9, v9, 0x1
:count_next
add-int/lit8 v10, v10, 0x1
goto :count_loop
:count_done
if-nez v9, :count_ok
const/4 v9, 0x1
:count_ok
new-array v10, v9, [Ljava/lang/String;
new-array v11, v9, [J
new-instance v12, Ljava/lang/StringBuilder;
invoke-direct {v12}, Ljava/lang/StringBuilder;-><init>()V
const/4 v13, 0x0
const/4 v14, 0x0
const-wide/16 v15, 0x0
const/16 v17, 0x0
:fill_loop
if-ge v13, v8, :fill_done
invoke-virtual {v7, v13}, Lorg/json/JSONArray;->getJSONObject(I)Lorg/json/JSONObject;
move-result-object v6
if-nez v17, :grp_open
const-string v9, "time"
invoke-virtual {v6, v9}, Lorg/json/JSONObject;->optLong(Ljava/lang/String;)J
move-result-wide v15
const/16 v17, 0x1
:grp_open
const-string v9, "text"
invoke-virtual {v6, v9}, Lorg/json/JSONObject;->optString(Ljava/lang/String;)Ljava/lang/String;
move-result-object v6
invoke-virtual {v12, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-static {v6, v13, v8}, Lradiant/WordLyrics;->isWordEnd(Ljava/lang/String;II)Z
move-result v6
if-eqz v6, :fill_next
invoke-virtual {v12}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
aput-object v6, v10, v14
aput-wide v15, v11, v14
add-int/lit8 v14, v14, 0x1
new-instance v12, Ljava/lang/StringBuilder;
invoke-direct {v12}, Ljava/lang/StringBuilder;-><init>()V
const/16 v17, 0x0
:fill_next
add-int/lit8 v13, v13, 0x1
goto :fill_loop
:fill_done
aput-object v10, v3, v5
aput-object v11, v4, v5
:line_next
# use the first WORD's start as the line's start so the active-line clock and the word times come from the same source (API line startTime can precede its words btw)
aget-object v6, v4, v5
const/4 v7, 0x0
aget-wide v8, v6, v7
aput-wide v8, v2, v5
add-int/lit8 v5, v5, 0x1
goto :line_loop
:lines_done
new-instance v6, Ljava/lang/StringBuilder;
const-string v7, "WordLyrics ingest: Word, lines="
invoke-direct {v6, v7}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v6, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
invoke-virtual {v6}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
invoke-static {v6}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
invoke-static {v2, v3, v4}, Lradiant/WordLyrics;->setData([J[[Ljava/lang/String;[[J)V
return-void
:try_end
.catchall {:try_start .. :try_end} :catch
:catch
move-exception v0
invoke-static {}, Lradiant/WordLyrics;->clear()V
return-void
.end method
# boundary if last char is whitespace or last syllable in the line
.method static isWordEnd(Ljava/lang/String;II)Z
.locals 3
add-int/lit8 v0, p2, -0x1
if-ne p1, v0, :not_last
const/4 v0, 0x1
return v0
:not_last
invoke-virtual {p0}, Ljava/lang/String;->length()I
move-result v0
if-nez v0, :has_len
const/4 v0, 0x0
return v0
:has_len
add-int/lit8 v1, v0, -0x1
invoke-virtual {p0, v1}, Ljava/lang/String;->charAt(I)C
move-result v1
invoke-static {v1}, Ljava/lang/Character;->isWhitespace(C)Z
move-result v1
return v1
.end method