Changeset View
Changeset View
Standalone View
Standalone View
extension/content-script.js
Show First 20 Lines • Show All 574 Lines • ▼ Show 20 Line(s) | 572 | ${mediaSessionsClassName}.sendMessage = function(action, payload) { | |||
---|---|---|---|---|---|
575 | var event = document.createEvent('CustomEvent'); | 575 | var event = document.createEvent('CustomEvent'); | ||
576 | event.initEvent('payloadChanged', true, true); | 576 | event.initEvent('payloadChanged', true, true); | ||
577 | this.transferItem.dispatchEvent(event); | 577 | this.transferItem.dispatchEvent(event); | ||
578 | }; | 578 | }; | ||
579 | ${mediaSessionsClassName}.executeCallback = function (action) { | 579 | ${mediaSessionsClassName}.executeCallback = function (action) { | ||
580 | this.callbacks[action](); | 580 | this.callbacks[action](); | ||
581 | }; | 581 | }; | ||
582 | 582 | | |||
583 | navigator.mediaSession = {}; | 583 | if (!navigator.mediaSession) { | ||
584 | navigator.mediaSession = function() {}; | ||||
fvogt: Why a function instead of an object now? | |||||
585 | } | ||||
586 | | ||||
587 | var noop = function() { }; | ||||
588 | | ||||
589 | var oldSetActionHandler = navigator.mediaSession.setActionHandler || noop; | ||||
584 | navigator.mediaSession.setActionHandler = function (name, cb) { | 590 | navigator.mediaSession.setActionHandler = function (name, cb) { | ||
591 | // Call the original native implementation | ||||
592 | // "call()" is needed as the real setActionHandler is a class member | ||||
593 | // and calling it directly is illegal as it lacks the context | ||||
594 | // We'll register the callback for ourself after this since it may | ||||
595 | // throw for unsupported callback names. | ||||
596 | var ret = oldSetActionHandler.call(navigator.mediaSession, name, cb); | ||||
597 | | ||||
585 | if (cb) { | 598 | if (cb) { | ||
586 | ${mediaSessionsClassName}.callbacks[name] = cb; | 599 | ${mediaSessionsClassName}.callbacks[name] = cb; | ||
587 | } else { | 600 | } else { | ||
588 | delete ${mediaSessionsClassName}.callbacks[name]; | 601 | delete ${mediaSessionsClassName}.callbacks[name]; | ||
589 | } | 602 | } | ||
590 | ${mediaSessionsClassName}.sendMessage("callbacks", Object.keys(${mediaSessionsClassName}.callbacks)); | 603 | ${mediaSessionsClassName}.sendMessage("callbacks", Object.keys(${mediaSessionsClassName}.callbacks)); | ||
604 | | ||||
605 | return ret; | ||||
591 | }; | 606 | }; | ||
607 | | ||||
592 | Object.defineProperty(navigator.mediaSession, "metadata", { | 608 | Object.defineProperty(navigator.mediaSession, "metadata", { | ||
593 | get: function() { return ${mediaSessionsClassName}.metadata; }, | 609 | get: function() { return ${mediaSessionsClassName}.metadata; }, | ||
594 | set: function(newValue) { | 610 | set: function(newValue) { | ||
595 | ${mediaSessionsClassName}.metadata = newValue; | 611 | ${mediaSessionsClassName}.metadata = newValue; | ||
596 | ${mediaSessionsClassName}.sendMessage("metadata", newValue ? newValue.data : null); | 612 | | ||
613 | // MediaMetadata is not a regular Object so we cannot just JSON.stringify it | ||||
614 | var newMetadata = {}; | ||||
615 | if (newValue) { | ||||
616 | var keys = Object.getOwnPropertyNames(Object.getPrototypeOf(newValue)); | ||||
617 | | ||||
618 | keys.forEach(function (key) { | ||||
619 | var value = newValue[key]; | ||||
620 | if (typeof value === "function") { | ||||
621 | return; // continue | ||||
622 | } | ||||
623 | newMetadata[key] = newValue[key]; | ||||
624 | }); | ||||
625 | } | ||||
626 | | ||||
627 | ${mediaSessionsClassName}.sendMessage("metadata", newMetadata); | ||||
597 | } | 628 | } | ||
598 | }); | 629 | }); | ||
599 | Object.defineProperty(navigator.mediaSession, "playbackState", { | 630 | Object.defineProperty(navigator.mediaSession, "playbackState", { | ||
600 | get: function() { return ${mediaSessionsClassName}.playbackState; }, | 631 | get: function() { return ${mediaSessionsClassName}.playbackState; }, | ||
601 | set: function(newValue) { | 632 | set: function(newValue) { | ||
602 | ${mediaSessionsClassName}.playbackState = newValue; | 633 | ${mediaSessionsClassName}.playbackState = newValue; | ||
603 | ${mediaSessionsClassName}.sendMessage("playbackState", newValue); | 634 | ${mediaSessionsClassName}.sendMessage("playbackState", newValue); | ||
604 | } | 635 | } | ||
605 | }); | 636 | }); | ||
606 | 637 | | |||
638 | if (!window.MediaMetadata) { | ||||
607 | window.MediaMetadata = function (data) { | 639 | window.MediaMetadata = function (data) { | ||
608 | this.data = data; | 640 | Object.assign(this, data); | ||
609 | }; | 641 | }; | ||
642 | window.MediaMetadata.prototype.title = ""; | ||||
643 | window.MediaMetadata.prototype.artist = ""; | ||||
644 | window.MediaMetadata.prototype.album = ""; | ||||
645 | window.MediaMetadata.prototype.artwork = []; | ||||
646 | } | ||||
610 | } | 647 | } | ||
611 | `); | 648 | `); | ||
612 | 649 | | |||
613 | // here we replace the document.createElement function with our own so we can detect | 650 | // here we replace the document.createElement function with our own so we can detect | ||
614 | // when an <audio> tag is created that is not added to the DOM which most pages do | 651 | // when an <audio> tag is created that is not added to the DOM which most pages do | ||
615 | // while a <video> tag typically ends up being displayed to the user, audio is not. | 652 | // while a <video> tag typically ends up being displayed to the user, audio is not. | ||
616 | // HACK We cannot really pass variables from the page's scope to our content-script's scope | 653 | // HACK We cannot really pass variables from the page's scope to our content-script's scope | ||
617 | // so we just blatantly insert the <audio> tag in the DOM and pick it up through our regular | 654 | // so we just blatantly insert the <audio> tag in the DOM and pick it up through our regular | ||
▲ Show 20 Lines • Show All 83 Lines • Show Last 20 Lines |
Why a function instead of an object now?