In recently, Google upgrade its cast receiver to version V3.
There is a simple demo in google demo page as below:
<html>
<head>
</head>
<body>
<cast-media-player id="player"></cast-media-player>
<style>
#player {
--theme-hue: 210;
--splash-image: url("my.png");
}
</style>
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
</script>
<script>
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
// intercept the LOAD request to be able to read in a contentId and get data
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD, loadRequestData => {
if (loadRequestData.media && loadRequestData.media.contentId) {
return thirdparty.getMediaById(loadRequestData.media.contentId)
.then(media => {
if (media) {
loadRequestData.media.contentUrl = media.url;
loadRequestData.media.contentType = media.contentType;
loadRequestData.media.metadata = media.metadata;
}
return loadRequestData;
});
}
return loadRequestData;
});
// listen to all Core Events
playerManager.addEventListener(cast.framework.events.category.CORE,
event => {
console.log(event);
});
const MyCastQueue = class extends cast.framework.QueueBase {
initialize(loadRequestData) {
const media = loadRequestData.media;
const items = [];
items.push(myCreateItem(media)); // your custom function logic
const queueData = new cast.framework.messages.QueueData();
queueData.items = items;
return queueData;
}
nextItems(itemId) {
return [myCreateNextItem()]; // your custom function logic
}
};
const playbackConfig = new cast.framework.PlaybackConfig();
// Sets the player to start playback as soon as there are five seconds of
// media contents buffered. Default is 10.
playbackConfig.autoResumeDuration = 5;
const myCastQueue = new MyCastQueue(); // create instance of queue Object
context.start({queue: myCastQueue, playbackConfig: playbackConfig});
</script>
</body>
</html>
From:
https://developers.google.com/cast/docs/caf_receiver_features#styling-the-player
But when I debugged it, there is an error that 'thirdparty' is undefined.
Does anyone can show me how to create a CAF receiver?
This is example code. You are supposed to provide those extra functions yourself.
The example shows how to override the queueing system to perform receiver based queueing. It isn't a great example IMHO as it doesn't provide an example of asynchronously fetching server based queues.
If you don't need receiver managed queues you can start with the minimal CAF receiver shown on the previous page. This is enough to get the remote debugger working which is at least one good reason to have a custom receiver.
https://developers.google.com/cast/docs/caf_receiver_basic
I've made a more complete example. https://gist.github.com/jcable/45c65a72074763a9ec30ddb1ff217517
Related
Using the HTML below, how can I get a list of the functions in the <script> tag that is IN the #yesplease div. I don't want any other functions from other script tags. I don't want any global functions or native functions. What I'd like is an array with "wantthis1" and "wantthis2" only in it. I'm hoping not to have to use regex.
I am going to be emptying and filling the #yesplease div with different strings of html (including new script tags with new functions), and I need to make sure that I delete or "wantthis1 = undefined" each function in the script tag before filling it, programmatically, since I won't know every function name. (I don't want them to remain in memory)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
function dontCare() {
// don't care
}
</script>
</head>
<body>
<div id="notthisone">
<p>
Hello
</p>
<script>
function dontwantthis () {
// nope
}
</script>
</div>
<div id="yesplease">
<p>
Hello again
</p>
<script>
function wantthis1 () {
// yes
}
function wantthis2 () {
// yes
}
</script>
</div>
<script>
// this function can be called by whatever, but this will look to
// see if functions exist, then call them, otherwise do something
// else
function onSaveOrWhatever () {
if (wantThis1 !== "undefined") {
wantThis1();
}
else {
// do something else (won't get called with above example)
}
if (wantThis3 !== "undefined") {
wantThis3();
}
else {
// do something else (will get called with above example)
}
}
</script>
</body>
</html>
Take innerHTML of all script tags you need
Create an iframe
Get a list of built-in functions of iframe.contentWindow object
Write the content of the script to the iframe created
Get a new list of the functions of iframe.contentWindow object
Find new functions added to the new list
Somehow it doesn't work in stack snippets but it works in Codepen link
var code = document.querySelector("#target script").innerHTML;
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var builtInFunctions = getFunctionsOfWindowObject();
var html = `<html><head><script>${code}</script></head><body /></html>`;
iframe.srcdoc = html;
var allFunctions = getFunctionsOfWindowObject();
var result = allFunctions.filter(function(n) {
return builtInFunctions.indexOf(n) < 0;
});
console.log(result);
function getFunctionsOfWindowObject() {
var functions = [];
var targetWindow = iframe.contentWindow;
for (var key in targetWindow) {
if (
targetWindow.hasOwnProperty(key) &&
typeof targetWindow[key] === "function"
) {
functions.push(key);
}
}
return functions;
}
iframe {
display: none;
}
<div id="target">
<script>
function wantthis1() {}
function wantthis2() {}
</script>
</div>
The are a few ways to solve this problem
Architect your application. Use react or vue (or even jquery) to add more control to your code/dom
AST parsing, which would be overkill
Hack it
If you hack it, the problem that you will face is that you are adding functions to global scope. This is shared by everyone, so you can't really monitor it in a nice way.
You can however take advantage of javascript singlethreadedness, and know that things won't happen in the background while you are doing monitoring tasks.
<script>
// take a cache of what is present before your script
window.itemsPresentBeforeScript = {};
foreach (var item in window) {
window.itemsPresentBeforeScript[item] = window[item];
}
</script>
<script> .... your other script </script>
<script>
// use your first cache to see what changed during the script execution
window.whatWasAddedInTheLastScript = {};
foreach (var item in window) {
if (!window.itemsPresentBeforeScript[item]) {
window.whatWasAddedInTheLastScript[item] = window[item];
}
}
delete window.itemsPresentBeforeScript;
// not you have a global list of what was added and you can clear it down when you need to
</script>
I am trying to call a function (widget.onTap()) in the following code
GestureDetector(
onTap: () {
widget.onTap()
},
child: Container(
height: 1.9 * widget.height,
width: 1.2 * widget.width,
child: HtmlElementView(viewType: 'liquid-button', key: UniqueKey(),),
),
)
I have registered my "liquid-button" as such
ui.platformViewRegistry.registerViewFactory('liquid-button', (int viewId) {
var element = html.IFrameElement()
..style.border = 'none'
..srcdoc = """
<!DOCTYPE html>
<head>
</head>
<body>
<svg class="liquid-button"
...
"""
return element;
});
The problem is I cannot capture anything from the user no matter what I try. The GestureDetector doesn't work, neither do the buttons. I am able to trigger some code in JS, but I need to handle it in Dart. Is this possible ?
I just found the workaround for this one.
So basically, we can take advantage of window.localStorage where it can be accessed from both flutter and html, and add listener in flutter for any change in window.localStorage
Add listener inside the flutter
final Storage webLocalStorage = window.localStorage;
htmlListener(){
String buttonClicked = webLocalStorage["buttonClicked"];
if(buttonClicked=="yes"){
//do whatever
}else{
Future.delayed(Duration(milliseconds: 100), (){
htmlListener();
});
}
}
Do some change to the webstorage in the HTML
var webLocalStorage = window.localStorage;
webLocalStorage["buttonClicked"] = "yes";
And you can do the same vice versa, that is listen from html, change in flutter.
My aim is to add buttons below my player that jump to specific moments in the video.
There's a demo example that does basically what I want:
https://flowplayer.com/demos/using-the-api — however it is based on the cloud player implementation of Flowplayer, and I'm using the Javascript API to embed my player. The basic relevant script is this:
flowplayer.cloud.then(function () {
var api = flowplayer("#player")
seek3.onclick = function() {
api.fas.seek_to('00:01:01:11');
}
});
An example I found of creating buttons using the Javascript API is as follows:
flowplayer(function(opts, root, api) {
// small jQuery-compatible utility built inside the player
var $ = flowplayer.mq;
// render a custom button when the player is mounted
api.on('mount', function() {
var btn = $('<button>').txt('Test Button').on('click', function() {
api.toggleMute();
});
$('.fp-controls', root).append(btn);
});
});
That works fine with my player. When I try to merge the two approaches, though, I fail. Here is the broken code:
flowplayer(function(opts, root, api) {
var api = flowplayer("#flowplayer");
seek3.onclick = function() {
api.fas.seek_to('00:01:01:11');
}
});
I tried also as alternatives
document.getElementById('seek3').onclick = function()
And
$('#seek1').onclick = function() {
(preceded by the additional line of code borrowed from the working example):
var $ = flowplayer.mq;
but with every variation I keep getting the following error: "Uncaught TypeError: Cannot set property 'onclick' of null".
Any help would be much appreciated. I've found the Flowplayer documentation really difficult to use, since in search results it's often hard to even tell which version of the player is being referenced. I would really like to find some basic info about interacting with the API in addition to solving this particular problem.
For anyone else who might be having difficulties interacting with the API, Flowplayer kindly posted a new demo example -- with similar functionality as in the cloudplayer demo, but this one for the javascript player: https://codepen.io/team/flowplayer/pen/KOzWOK
var api = flowplayer("#player",
{ src : "//edge.flowplayer.org/drive.m3u8"
, autoplay : false
, token : "eyJraWQiOiJqOEF6djg5NlJMMWIiLCJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJjIjoie1wiYWNsXCI6NixcImlkXCI6XCJqOEF6djg5NlJMMWJcIixcImRvbWFpblwiOltcIm5ncm9rLmlvXCJdfSIsImlzcyI6IkZsb3dwbGF5ZXIifQ.UtJliSh4IcIKs71PVzXWdIrJJ8-1_KRK0hKd7OKp5EJhAdpZStuYbbU4bgDs--C6Gak6OBrb-xQBh6sd4dyrlA"
, muted : true
})
/**
* helper function to seek if possible or
* tell the player to seek when possible
*
* btn {HTMLElement}
* seconds {Number}
*/
function chapter (btn, seconds) {
btn.onclick = function () {
// player is preload=none so we must tell
// the player to seek when it is possible
if (api.readyState == 0) api.setOpts({start_time: seconds})
// player has already started loading content
if (api.readyState > 0) api.currentTime = seconds
// attempt to play content
api.togglePlay(true)
}
}
// bind the buttons to times
chapter(seek1, 20)
chapter(seek2, 45)
chapter(seek3, 60)
My working version includes the following variations on the JS code:
/**
* helper function to seek if possible or
* tell the player to seek when possible
*
* seconds {Number}
*/
function seek_to_cue (seconds) {
//alert('bingo?'); //tft
// player is preload=none so we must tell the player to seek when it is possible
if (api.readyState == 0) {
api.setOpts({start_time: seconds});
}
// player has already started loading content
if (api.readyState > 0) {
api.currentTime = seconds;
}
// attempt to play content
api.togglePlay(true);
}
and in my PHP code which includes the JS player call:
$button_actions .= 'document.getElementById("'.$button_id.'").addEventListener("click", function(){ seek_to_cue('.$start_time_seconds.'); });';
I'm writing a website using VueJS which allows (selected) users to add scripts that are automatically executed upon page load. Here's a sample text that a user might upload:
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js"></script>
<script>
var sound = new howler.Howl({
src: ['./sample.mp3']
)}.play();
</script>
This text is stored into a string after retrieving from API backend. The problem now is: I couldn't get it to execute however I try. Is there an option in VueJS that can automatically execute javascripts in strings?
As a reference, here's my code:
var temp_arr = utils.preprocess(vm.chapterInfo.Content)
vm.display = temp_arr[0]
vm.control_script = console.log(temp_arr[1])
// None of below worked
eval(vm.control_script)
document.getElementsByTagName("head")[0].appendChild(control_script)
The problem isn't a Vue one, but a JavaScript one.
I assume that you already understand the security implications of allowing users to run JavaScript; it's rarely a good idea. Sites like JSFiddle do it successfully, however it will take a lot of work and understanding to make it safe, so if you're not 100% sure with what you are doing, then as #WaldemarIce said, you shouldn't do it!
Right, with the warning out the way, you need to do a few things to get this to work:
1) Load the external scripts:
loadScripts() {
return new Promise(resolve => {
let scriptEl = document.createElement("script");
scriptEl.src = "https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.5/howler.js";
scriptEl.type = "text/javascript";
// Attach script to head
document.getElementsByTagName("head")[0].appendChild(scriptEl);
// Wait for tag to load before promise is resolved
scriptEl.addEventListener('load',() => {
resolve();
});
});
}
Here I'm simply attaching the external script to the head of the document and attaching a load event, which resolves the Promise when loaded.
2) Now we have loaded the external script we can execute the remainder of the script. You will need to strip out the script tags, so you can do something like this:
executeScript() {
// remove script tags from string (this has been declared globally)
let script = string.replace(/<\/?script>/g,"")
eval(script)
}
Form the Vue perspective, you can then execute this inside the created hook:
created() {
this.loadScripts().then(() => {
this.executeScript();
});
},
I'll leave it to you to extract the external scripts you want to load from your user input, but here's a JSFiddle: https://jsfiddle.net/49dq563d/
I recently came across this problem and had to extend on the answer from #craig_h. The example below allows full embed code to be sent through as string (HTML elements as well as scripts and inline JS). This is using DOMParser.
<div ref="htmlDump"></div>
<script>
import Vue from "vue";
export default {
...
methods: {
cloneAttributes(element, sourceNode) {
let attr;
let attributes = Array.prototype.slice.call(sourceNode.attributes);
while(attr = attributes.pop()) {
element.setAttribute(attr.nodeName, attr.nodeValue);
}
}
},
mounted(){
if(this.embedString && this.embedString.length > 0)
{
//Parse the code given from the API into a new DOM so we can easily manipulate it
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(this.embedString, 'text/html');
//Get the contents of the new DOM body and loop through.
//We want to add all HTML elements to the page and run / load all JS
var kids = [...htmlDoc.body.children];
let len = kids.length;
for (var i = 0; i < len; i++) {
var item = kids[i];
if(item.tagName == "SCRIPT")
{
//If we have a 'src' attribute then we're loading in a script
if(item.hasAttribute('src'))
{
//Create a new element within the current doc to trigger the script load
let scriptEl = document.createElement("script");
//Copy all attributes from the source element to the new one
this.cloneAttributes(scriptEl, item);
//Attach script to the DOM to trigger it to load
this.$refs.htmlDump.appendChild(scriptEl);
} else {
//if we don't have a 'src' attribute then we have some code to run
eval(item.innerText);
}
} else{
this.$refs.htmlDump.appendChild(item);
}
}
}
}
...
}
</script>
THis topic is abouton google add word (conversation)
Below is my conversation setup screenshot
http://nimb.ws/alycTQ
Below is my code that was putted on body tag
<script type="text/javascript">
/* <![CDATA[ */
function GoogleFormTracker()
{
goog_snippet_vars = function() {
var w = window;
w.google_conversion_id = 949468534;
w.google_conversion_label = "9xLwCK7rm3IQ9vrexAM";
w.google_conversion_value = 1;
w.google_remarketing_only = false;
}
// DO NOT CHANGE THE CODE BELOW.
goog_report_conversion = function(url) {
goog_snippet_vars();
window.google_conversion_format = "3";
var opt = new Object();
opt.onload_callback = function() {
if (typeof(url) != 'undefined') {
window.location = url;
}
}
var conv_handler = window['google_trackConversion'];
if (typeof(conv_handler) == 'function') {
conv_handler(opt);
}
}
}
/* ]]> */
</script>
<script type="text/javascript"
src="//www.googleadservices.com/pagead/conversion_async.js">
</script>
GoogleFormTracker() fired on footer when site is load.
And also i verified my code on tag manager chrome addons(No error showing there).
but i don't know where to showing me how many time this function is fired ?
let me know any mistake in my code or where is showing tracking value in add word (with screenshot and step by step).
Thanks
In google add word account follow below step
Tool->Attribution
In Attribution available you conversation value.
I hope u need like above
"but i don't know where to showing me how many time this function is fired". Not entirely sure I understand, but perhaps you just need to put a console.log('marco'); inside the function and view the browser console (ctrl + shift + i) to see how many times the function is called?