Files @ bbff83207963
Branch filter:

Location: light9/web/light9-vidref-replay-stack.js

bbff83207963 5.5 KiB application/javascript Show Annotation Show as Raw Download as Raw
drewp@bigasterisk.com
minor cleanups and timings
import { LitElement, TemplateResult, html, css } from '/node_modules/lit-element/lit-element.js';
import debug from '/lib/debug/debug-build-es6.js';
import _ from '/lib/underscore/underscore-min-es6.js';
import { rounding }  from '/node_modules/significant-rounding/index.js';

const log = debug('stack');

class Light9VidrefReplayStack extends LitElement {
    
    static get properties() {
        return {
            songTime: { type: Number, attribute: false }, // from musicState.t but higher res
            musicState: { type: Object, attribute: false },
            players: { type: Array, attribute: false },
            size: { type: String, attribute: true }
        };
    }

    constructor() {
        super();
        this.musicState = {};
    }

    setVideoTimesFromSongTime() {
        this.shadowRoot.querySelectorAll('light9-vidref-replay').forEach(
            (r) => {
                r.setVideoTimeFromSongTime(this.songTime, this.musicState.playing);
            });
    }
    nudgeTime(dt) {
        this.songTime += dt;
        log('song now', this.songTime);
    }
    fineTime() {
        if (this.musicState.playing) {
            const sinceLastUpdate = (Date.now() - this.musicState.reportTime) / 1000;
            this.songTime = sinceLastUpdate + this.musicState.tStart;
        } else if (this.lastFineTimePlayingState)  {
            this.songTime = this.musicState.t;
        }
        this.lastFineTimePlayingState = this.musicState.playing;
        requestAnimationFrame(this.fineTime.bind(this));
    }

    updated(changedProperties) {
        if (changedProperties.has('songTime')) {
            this.setVideoTimesFromSongTime();
        }
    }

    firstUpdated() {
        this.songTimeRangeInput = this.shadowRoot.querySelector('#songTime');

        const ws = reconnectingWebSocket('../ascoltami/time/stream',
                                         this.receivedSongAndTime.bind(this));
        reconnectingWebSocket('../vidref/time/stream', this.receivedRemoteScrubbedTime.bind(this));
        // bug: upon connecting, clear this.song
        this.fineTime();
    }

    receivedSongAndTime(msg) {
        this.musicState = msg;
        this.musicState.reportTime = Date.now();
        this.musicState.tStart = this.musicState.t;            

        this.songTimeRangeInput.max = this.musicState.duration;

        if (this.musicState.song != this.song) {
            this.song = this.musicState.song;
            this.getReplayMapForSong(this.song);
        }
    }

    receivedRemoteScrubbedTime(msg) {
        this.songTime = msg.st;

        // This doesn't work completely since it will keep getting
        // updates from ascoltami slow updates.
        if (msg.song != this.song) {
            this.song = msg.song;
            this.getReplayMapForSong(this.song);
        }
    }
        
    getReplayMapForSong(song) {
        const u = new URL(window.location.href);
        u.pathname = '/vidref/replayMap'
        u.searchParams.set('song', song);
        u.searchParams.set('maxClips', this.size == "small" ? '1' : '3');
        fetch(u.toString()).then((resp) => {
            if (resp.ok) {
                resp.json().then((msg) => {
                    this.players = msg.map(this.makeClipRow.bind(this));
                    this.updateComplete.then(this.setupClipRows.bind(this, msg));
                });
            }
        });          
    }
    
    setupClipRows(msg) {
        const nodes = this.shadowRoot.querySelectorAll('light9-vidref-replay');
        nodes.forEach((node, i) => {
            node.uri = msg[i].uri;
            node.videoUrl = msg[i].videoUrl;
            node.songToVideo = msg[i].songToVideo;
        });
        this.setVideoTimesFromSongTime();
    }
    
    makeClipRow(clip) {
        return html`<light9-vidref-replay @clips-changed="${this.onClipsChanged}" size="${this.size}"></light9-vidref-replay>`;
    }
    
    onClipsChanged(ev) {
        this.getReplayMapForSong(this.song);
    }
    
    disconnectedCallback() {
        log('bye');
        //close socket
    }

    userMovedSongTime(ev) {
        const st = this.songTimeRangeInput.valueAsNumber;
        this.songTime = st;

        fetch('/ascoltami/seekPlayOrPause', {
            method: 'POST',
            body: JSON.stringify({scrub: st}),
        });
    }

    static get styles() {
        return css`
        :host {
           display: inline-block;
        }
        #songTime {
            width: 100%;
        }
        #clips {
            display: flex;
            flex-direction: column;
        }
        a {
            color: rgb(97, 97, 255);
        }
        #songTime {
            font-size: 27px;
        }
        light9-vidref-replay {
            margin: 5px;
        }
        `;
    }
    
    render() {
        const songTimeRange = this.size != "small" ? html`<input id="songTime" type="range" 
           .value="${this.songTime}" 
           @input="${this.userMovedSongTime}" 
           min="0" max="0" step=".001"></div>
  <div><a href="${this.musicState.song}">${this.musicState.song}</a></div>` : '';


        const globalCommands = this.size != 'small' ? html`
  <div>
    <button @click="${this.onClipsChanged}">Refresh clips for song</button>
  </div>
` : '';
        return html`
  <div>
    ${songTimeRange}
  <div id="songTime">showing song time ${rounding(this.songTime, 3)}</div>
  <div>clips:</div>
  <div id="clips">
    ${this.players}
  </div>
  ${globalCommands}
`;

    }
}
customElements.define('light9-vidref-replay-stack', Light9VidrefReplayStack);