comparison web/light9-vidref-replay-stack.js @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents light9/web/light9-vidref-replay-stack.js@286a34d9ccba
children
comparison
equal deleted inserted replaced
2375:623836db99af 2376:4556eebe5d73
1 import { LitElement, TemplateResult, html, css } from '/node_modules/lit-element/lit-element.js';
2 import debug from '/lib/debug/debug-build-es6.js';
3 import _ from '/lib/underscore/underscore-min-es6.js';
4 import { rounding } from '/node_modules/significant-rounding/index.js';
5
6 const log = debug('stack');
7
8 class Light9VidrefReplayStack extends LitElement {
9
10 static get properties() {
11 return {
12 songTime: { type: Number, attribute: false }, // from musicState.t but higher res
13 musicState: { type: Object, attribute: false },
14 players: { type: Array, attribute: false },
15 size: { type: String, attribute: true }
16 };
17 }
18
19 constructor() {
20 super();
21 this.musicState = {};
22 }
23
24 setVideoTimesFromSongTime() {
25 this.shadowRoot.querySelectorAll('light9-vidref-replay').forEach(
26 (r) => {
27 r.setVideoTimeFromSongTime(this.songTime, this.musicState.playing);
28 });
29 }
30 nudgeTime(dt) {
31 this.songTime += dt;
32 log('song now', this.songTime);
33 }
34 fineTime() {
35 if (this.musicState.playing) {
36 const sinceLastUpdate = (Date.now() - this.musicState.reportTime) / 1000;
37 this.songTime = sinceLastUpdate + this.musicState.tStart;
38 } else if (this.lastFineTimePlayingState) {
39 this.songTime = this.musicState.t;
40 }
41 this.lastFineTimePlayingState = this.musicState.playing;
42 requestAnimationFrame(this.fineTime.bind(this));
43 }
44
45 updated(changedProperties) {
46 if (changedProperties.has('songTime')) {
47 this.setVideoTimesFromSongTime();
48 }
49 }
50
51 firstUpdated() {
52 this.songTimeRangeInput = this.shadowRoot.querySelector('#songTime');
53
54 const ws = reconnectingWebSocket('../ascoltami/time/stream',
55 this.receivedSongAndTime.bind(this));
56 reconnectingWebSocket('../vidref/time/stream', this.receivedRemoteScrubbedTime.bind(this));
57 // bug: upon connecting, clear this.song
58 this.fineTime();
59 }
60
61 receivedSongAndTime(msg) {
62 this.musicState = msg;
63 this.musicState.reportTime = Date.now();
64 this.musicState.tStart = this.musicState.t;
65
66 this.songTimeRangeInput.max = this.musicState.duration;
67
68 if (this.musicState.song != this.song) {
69 this.song = this.musicState.song;
70 this.getReplayMapForSong(this.song);
71 }
72 }
73
74 receivedRemoteScrubbedTime(msg) {
75 this.songTime = msg.st;
76
77 // This doesn't work completely since it will keep getting
78 // updates from ascoltami slow updates.
79 if (msg.song != this.song) {
80 this.song = msg.song;
81 this.getReplayMapForSong(this.song);
82 }
83 }
84
85 getReplayMapForSong(song) {
86 const u = new URL(window.location.href);
87 u.pathname = '/vidref/replayMap'
88 u.searchParams.set('song', song);
89 u.searchParams.set('maxClips', this.size == "small" ? '1' : '3');
90 fetch(u.toString()).then((resp) => {
91 if (resp.ok) {
92 resp.json().then((msg) => {
93 this.players = msg.map(this.makeClipRow.bind(this));
94 this.updateComplete.then(this.setupClipRows.bind(this, msg));
95 });
96 }
97 });
98 }
99
100 setupClipRows(msg) {
101 const nodes = this.shadowRoot.querySelectorAll('light9-vidref-replay');
102 nodes.forEach((node, i) => {
103 node.uri = msg[i].uri;
104 node.videoUrl = msg[i].videoUrl;
105 node.songToVideo = msg[i].songToVideo;
106 });
107 this.setVideoTimesFromSongTime();
108 }
109
110 makeClipRow(clip) {
111 return html`<light9-vidref-replay @clips-changed="${this.onClipsChanged}" size="${this.size}"></light9-vidref-replay>`;
112 }
113
114 onClipsChanged(ev) {
115 this.getReplayMapForSong(this.song);
116 }
117
118 disconnectedCallback() {
119 log('bye');
120 //close socket
121 }
122
123 userMovedSongTime(ev) {
124 const st = this.songTimeRangeInput.valueAsNumber;
125 this.songTime = st;
126
127 fetch('/ascoltami/seekPlayOrPause', {
128 method: 'POST',
129 body: JSON.stringify({scrub: st}),
130 });
131 }
132
133 static get styles() {
134 return css`
135 :host {
136 display: inline-block;
137 }
138 #songTime {
139 width: 100%;
140 }
141 #clips {
142 display: flex;
143 flex-direction: column;
144 }
145 a {
146 color: rgb(97, 97, 255);
147 }
148 #songTime {
149 font-size: 27px;
150 }
151 light9-vidref-replay {
152 margin: 5px;
153 }
154 `;
155 }
156
157 render() {
158 const songTimeRange = this.size != "small" ? html`<input id="songTime" type="range"
159 .value="${this.songTime}"
160 @input="${this.userMovedSongTime}"
161 min="0" max="0" step=".001"></div>
162 <div><a href="${this.musicState.song}">${this.musicState.song}</a></div>` : '';
163
164
165 const globalCommands = this.size != 'small' ? html`
166 <div>
167 <button @click="${this.onClipsChanged}">Refresh clips for song</button>
168 </div>
169 ` : '';
170 return html`
171 <div>
172 ${songTimeRange}
173 <div id="songTime">showing song time ${rounding(this.songTime, 3)}</div>
174 <div>clips:</div>
175 <div id="clips">
176 ${this.players}
177 </div>
178 ${globalCommands}
179 `;
180
181 }
182 }
183 customElements.define('light9-vidref-replay-stack', Light9VidrefReplayStack);