display custom error message in a live Player - javascript

I have a react code as shown below which renders player on page load. The code goes inside the if block only if the condition is true.
const player = ()=> {
if(condition) {
return (
<ReactJWPlayer
playlist={[props.playlist]}
/>
)
}
}
Problem Statement: For the error code 232011, I am seeing the following error message:
[![enter image description here][1]][1]
This video file cannot be played
(Error Code: 232011)
I am wondering what changes I need to make in the react code above so that I can replace the above error message with the following one in the player.
Video will be available soon

You have to use intl.{lang}.errors object. This object localizes the error messages displayed in the player.
In order to configure intl.{lang}.errors, you will have to use customProps option exposed by react-jw-player to be applied directly to the JW Player instance.
You can stick with en only, or add additional language support depending on your use-case.
import { useRef } from "react";
import ReactJWPlayer from "react-jw-player";
import ReactDOM from "react-dom";
export default function App() {
const jwPlayerRef = useRef();
const myErrorHandler = (err) => {
console.log(err);
// Find the Node where error message is shown
const errorNode = ReactDOM.findDOMNode(
jwPlayerRef.current
).getElementsByClassName("jw-error-text");
// If the error node exists, replace both message and code
if (errorNode && errorNode.length)
errorNode[0].innerText = "Custom Error Message";
};
return (
<div className="App">
<div
className="jw-video-container"
data-mediaid="TAITbudl"
style={{ height: "100%", width: "100%" }}
>
<ReactJWPlayer
ref={jwPlayerRef}
playerId="TAITbudl"
playerScript="https://content.jwplatform.com/libraries/j9BLvpMc.js"
playlist="https://cdn.jwplayer.com/v2/media/123"
onError={myErrorHandler}
onSetupError={myErrorHandler}
customProps={{ // <= Official way to override the error message
intl: {
en: {
errors: {
badConnection:
"This video cannot be played because of a problem with your internet connection.",
cantLoadPlayer: "Sorry, the video player failed to load.",
cantPlayInBrowser:
"The video cannot be played in this browser.",
cantPlayVideo: "This is my custom error Message",
errorCode: "Code - ",
liveStreamDown:
"The live stream is either down or has ended.",
protectedContent:
"There was a problem providing access to protected content.",
technicalError:
"This video cannot be played because of a technical error."
}
}
}
}}
/>
</div>
</div>
);
}
The intl object allows you to add new language translations, [...] - Docs
Note that getElementsByClassName("jw-error-text") is a hack, and if JW Player decided to change the class name, or obfuscate it, this hack will break.

Related

Web Worker with imported modules in React

I'm trying to make a web worker to prevent stalling the React main thread. The worker is supposed to read an image and do various things.
The app was created using create-react-app.
Currently I have
WebWorker.js
export default class WebWorker {
constructor(worker) {
const code = worker.toString();
const blob = new Blob(['('+code+')()'], {type: "text/javascript"});
return new Worker(URL.createObjectURL(blob), {type: 'module'});
}
}
readimage.worker.js
import Jimp from "jimp";
export default () => {
self.addEventListener('message', e => { // eslint-disable-line no-restricted-globals
if (!e) return;
console.log('Worker reading pixels for url', e.data);
let data = {};
Jimp.read(e.data).then(image => {
// jimp does stuff
console.log('Worker Finished processing image');
})
postMessage(data);
})
};
And then in my React component AppContent.js I have
import WebWorker from "./workers/WebWorker";
import readImageWorker from './workers/readimage.worker.js';
export default function AppContent() {
const readWorker = new ReadImageWorker(readImageWorker);
readWorker.addEventListener('message', event => {
console.log('returned data', event.data);
setState(data);
});
// callback that is executed onClick from a button component
const readImageContents = (url) => {
readWorker.postMessage(url);
console.log('finished reading pixels');
};
}
But when I run it, I get the error
Uncaught ReferenceError: jimp__WEBPACK_IMPORTED_MODULE_0___default is not defined
How can I properly import a module into a web worker?
EDIT:
As per suggestions from Kaiido, I have tried installing worker-loader, and edited my webpack.config.js to the following:
module.exports = {
module: {
rules: [
{
test: /\.worker\.js$/,
use: { loader: 'worker-loader' }
}
]
}
};
But when I run it, I still get the error
Uncaught ReferenceError: jimp__WEBPACK_IMPORTED_MODULE_0__ is not defined
I'm not too much into React, so I can't tell if the module-Worker is the best way to go (maybe worker-loader would be a better solution), but regarding the last error you got, it's because you didn't set the type of your Blob when you built it.
In this case, it does matter, because it will determine the Content-Type the browser sets when serving it to the APIs that fetch it.
Here Firefox is a bit more lenient and somehow allows it, but Chrome is picky and requires you set this type option to one of the many javascript MIME-types.
const script_content = `postMessage('running');`;
// this one will fail in Chrome
const blob1 = new Blob([script_content]); // no type option
const worker1 = new Worker(URL.createObjectURL(blob1), { type: 'module'});
worker1.onerror = (evt) => console.log( 'worker-1 failed' );
worker1.onmessage = (evt) => console.log( 'worker-1', evt.data );
// this one works in Chrome
const blob2 = new Blob([script_content], { type: "text/javascript" });
const worker2 = new Worker(URL.createObjectURL(blob2), { type: 'module'});
worker2.onerror = (evt) => console.log( 'worker-2 failed' );
worker2.onmessage = (evt) => console.log( 'worker-2', evt.data );
But now that this error is fixed, you'll face an other error, because the format import lib from "libraryname" is still not supported in browsers, so you'd have to change "libraryname" to the path to your actual script file, keeping in mind that it will be relative to your Worker's base URI, i.e probably your main-page's origin.
I experienced the same problem. Firefox could not show me where exactly the error was (in fact it was plain misleading...) but Chrome did.
I fixed my problem by not relying on an import statement (importing one of my other files) which would only have worked within a React context. When you load a Worker script (via the blob()
/ URL() hack), it has no React context (as it is loaded at runtime and not at transpile time). So all the React paraphernalia __WEBPACK__blah_blah is not going to exist / be visible.
So... within react... import statements in worker files will not work.
I haven't thought of a workaround yet.

How to correctly get user information in React/Redux/OIDC

Fairly new to OIDC - I've done a bit of work with it in the past, but I wouldn't call myself an expert by any means.
I am trying to use OIDC in a react app using the oidc-client-js and redux-oidc libraries (along with the redux-oidc-example as an example)
I'm getting this error:
Error: No matching state found in storage
at eval (oidc-client.min.js:1011)
Now I've looked around for a solution to this, and this is the closest I'm seeing to my problem, but I still don't find anything here clearly explaining anything:
https://github.com/IdentityModel/oidc-client-js/issues/648
Here's my callback function:
const successCallback = (user) => {
this.props.dispatch(push("/settings"))
};
class CallbackPage extends React.Component {
render() {
return (
<CallbackComponent
userManager={userManager}
successCallback={successCallback}
errorCallback={error => {
//this.props.dispatch(push("/chat"));
console.error(error);
}}
>
<div>Redirecting TEST...</div>
</CallbackComponent>
);
}
}
export default connect()(CallbackPage);
Before commenting out the props.dispatch in the error callback, it was a never-ending loop. Now it just freezes on the callback page with whatever I put in the error callback.
I won't put my full userManager settings, as that seems like it would be excessive, but here are some of the main highlights:
{
"authority": "https://subdomain.appname.com/auth/realms/appname/",
"client_id": "appname-app",
"redirect_uri": "http://localhost:3001/callback",
"response_type": "code",
"extraQueryParams": {"kc_idp_hint": "google"},
"loadUserInfo": true,
"scope": ["openid", "profile", "email"]
}
I'm not sure what else would be helpful to anyone troubleshooting it - I can give my store.js information or my main application index.js if needed.
Scope paramenter for user meneger should be space separated string and not an array.
Example: 'openid profile email'
Try this.
class CallbackPage extends React.Component {
successCallback = (user) => {
this.props.dispatch(push("/settings"))
};
render() {
return (
<CallbackComponent
userManager={userManager}
successCallback={this.successCallback}
errorCallback={error => {
//this.props.dispatch(push("/chat"));
console.error(error);
}}
>
<div>Redirecting TEST...</div>
</CallbackComponent>
);
}
}
export default connect()(CallbackPage);

Can you track background geolocation with React Native?

Problem
I'd like to be able to track a users location even when the app is no longer in the foreground (e.g. The user has switch to another app or switched to the home screen and locked their phone).
The use case would be a user tracking a run. They could open the app and press 'start' at the beginning of their run, then switch or minimise the app (press the home button) and lock the screen. At the end of the run they could bring the app into the foreground and press 'stop' and the app would tell them distance travelled on the run.
Question
Is tracking background geolocation possible on both iOS and Android using pure react native?
The react native docs on geolocation (https://facebook.github.io/react-native/docs/geolocation) are not very clear or detailed. The documented linked above eludes to background geolocation on iOS (without being fully clear) but does not mention Android.
Would it be best that I use Expo?
UPDATE 2019 EXPO 33.0.0:
Expo first deprecated it for their SDK 32.0.0 to meet app store guidelines but then reopened it in SDK 33.0.0.
Since, they have made it super easy to be able to implement background location. Use this code snippet that I used to make background geolocation work.
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
import * as TaskManager from 'expo-task-manager';
import * as Location from 'expo-location';
const LOCATION_TASK_NAME = 'background-location-task';
export default class Component extends React.Component {
onPress = async () => {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
timeInterval: 5000,
});
};
render() {
return (
<TouchableOpacity onPress={this.onPress} style={{marginTop: 100}}>
<Text>Enable background location</Text>
</TouchableOpacity>
);
}
}
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
alert(error)
// Error occurred - check `error.message` for more details.
return;
}
if (data) {
const { locations } = data;
alert(JSON.stringify(locations); //will show you the location object
//lat is locations[0].coords.latitude & long is locations[0].coords.longitude
// do something with the locations captured in the background, possibly post to your server with axios or fetch API
}
});
The code works like a charm. One thing to note is that you cannot use geolocation in the Expo App. However, you can use it in your standalone build. Consequently, if you want to use background geolocation you have to use this code and then do expo build:ios and upload to the appstore in order to be able to get a users background location.
Additionally, note that you must include
"UIBackgroundModes":[
"location",
"fetch"
]
In the info.plist section of your app.json file.
The Expo Team release a new feature in SDK 32 that allow you tracking in background the location.
https://expo.canny.io/feature-requests/p/background-location-tracking
Yes is possible, but not using Expo, there are two modules that I've seen:
This is a comercial one, you have to buy a license https://github.com/transistorsoft/react-native-background-geolocation
And this https://github.com/mauron85/react-native-background-geolocation
Webkit is currently evaluating a Javascript-only solution. You can add your voice here
For a fully documented proof-of-concept example please see Brotkrumen.
The most popular RN geolocation library is https://github.com/react-native-geolocation/react-native-geolocation, and it supports this quite easily. I prefer this library over others because it automatically handles asking for permissions and such, and seems to have the simplest API.
Just do this:
Geolocation.watchPosition((position)=>{
const {latitude, longitude} = position.coords;
// Do something.
})
This requires no additional setup other than including the background modes fetch and location, and also the appropriate usage descriptions.
I find this more usable than Expo's API because it doesn't require any weird top level code and also doesn't require me to do anything other than create a watch position handler, which is really nice.
EDIT 2023!:
These days I would highly recommend using Expo's library instead of any of the other community libraries (mainly because our app started crashing when android got an OS update b/c of the lib I was using).
In fact, if you have to choose between expo and non expo library, always choose the expo library if only for the stability. Setting up expo's background location watching isn't super well documented but here's what I did to get it working in our app:
import { useEffect, useRef } from "react";
import * as Location from "expo-location";
import { LatLng } from "react-native-maps";
import * as TaskManager from "expo-task-manager";
import { LocationObject } from "expo-location";
import { v4 } from "uuid";
type Callback = (coords: LatLng) => void;
const BACKGROUND_TASK_NAME = "background";
const executor: (body: TaskManager.TaskManagerTaskBody<object>) => void = (
body
) => {
const data = body.data as unknown as { locations: LocationObject[] };
const l = data?.locations[0];
if (!l) return;
for (const callback of Object.values(locationCallbacks)) {
callback({
latitude: l.coords.latitude,
longitude: l.coords.longitude,
});
}
};
TaskManager.defineTask(BACKGROUND_TASK_NAME, executor);
const locationCallbacks: { [key: string]: Callback } = {};
const hasStartedBackgroundTaskRef = {
hasStarted: false,
};
function startBackgroundTaskIfNecessary() {
if (hasStartedBackgroundTaskRef.hasStarted) return;
Location.startLocationUpdatesAsync(BACKGROUND_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
}).catch((e) => {
hasStartedBackgroundTaskRef.hasStarted = false;
});
hasStartedBackgroundTaskRef.hasStarted = true;
}
function addLocationCallback(callback: Callback) {
const id = v4() as string;
locationCallbacks[id] = callback;
return {
remove: () => {
delete locationCallbacks[id];
},
};
}
export default function useLocationChangeListener(
callback: Callback | null,
active: boolean = true
) {
const callbackRef = useRef<null | Callback>(callback);
callbackRef.current = callback;
useEffect(() => {
if (!active) return;
if (!callback) return;
Location.getLastKnownPositionAsync().then((l) => {
if (l)
callback({
latitude: l.coords.latitude,
longitude: l.coords.longitude,
});
});
startBackgroundTaskIfNecessary();
const watch = Location.watchPositionAsync({}, (location) => {
callback({
latitude: location.coords.latitude,
longitude: location.coords.longitude,
});
});
const subscription = addLocationCallback(callback);
return () => {
subscription.remove();
watch.then((e) => {
e.remove();
});
};
}, [callback, active]);
useEffect(() => {
if (__DEV__) {
addLocationCallback((coords) => {
console.log("Location changed to ");
console.log(coords);
});
}
}, []);
}
You need to ask for background location permissions before this, BTW. Follow expos guide.
It's pretty risky trusting community libraries for stuff like this because of the fact that breaking android OS updates can happen at any moment and with open source maintainers they may or may not stay on top of it (you can more or less trust expo too, though)

Using WaveSurfer.js v2 in React Component

I'm trying to use WaveSurfer.js(version 2) with React.
I know that for version 1 there was a library called react-wavesurfer, but I really want to do it with v2.
I'm already experienced with it, without React. So, I just made a component of mine.
As you can see in the code below, it all works perfectly, the WaveSurfer object is generated correctly in the componentDidMount() but then, all of sudden, in the load() method, there's an error I can't understand correctly.
This error is throwed after the load(), and after the error, it's logged in console "There it happens!" and the wave property of the state, as it should be.
This is the error in question and by itself it doesn't mean nothing. That's just an error without stack trace in a obfuscated function in react-error-overlay. The second error, DOMException, is directly caused by the first, and they everytime are throwed together.
This is the row of the react-error-overlay that causes the error directly, in /node_modules/react-error-overlay/index.js:1582, but it's obfuscated.
// ... various imports
class Track extends Component {
wavref = null;
constructor(props) {
super(props);
let id = this.props.id;
this.state = {
id: id,
wave: null
};
}
load() {
console.log(this.state.wave, this.props.audio); // this.props.audio is the correct path, and should work correctly: "../../demo.wav".
this.state.wave.load(this.props.audio);
console.log("There it happens!", this.state.wave);
}
componentDidMount() {
let generatedWave = WaveSurfer.create({
container: ReactDOM.findDOMNode(this.waveref),
waveColor: this.state.color,
progressColor: this.state.progressColor,
plugins: [
RegionsPlugin.create({
dragSelection: {
slop: 5
}
}),
CursorPlugin.create({})
]
});
this.setState({
wave: generatedWave,
}, function() {
this.load();
});
}
render() {
return(
<div ref={(waveref) => this.waveref = waveref}></div>
);
}
}
export default Track;
Obviously, the load() method doesn't load/render the actual wave in the WaveSurfer canvas, and throws that error. I can't understand why, because it should just work normally and render the wave in the WaveSurfer canvas.
Does anyone of you know what can the error be?

Antd upload's Dragger component upload occurs across domains

I use create-react-app to do my front end, and use the Dragger component inside antd's upload. My backend is springboot. My front end sends request data to the backend using fetch, which will cause cross-domain problems. So I added "proxy" in the package.json file of create-react-app: "http://localhost:8080" to proxy my backend, which solves the trouble of cross-domain, but when I use antd official website The uploader's Dragger component always reports an error when uploading.
This is my code for using Antd's Dragger.
import React, { Component } from 'react';
import { Upload, Icon, message } from 'antd';
import './UpVideo.css';
const Dragger = Upload.Dragger;
export default class UpVideo extends Component {
render(){
const props = {
name: 'file',
multiple: false,
headers:{
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'POST',
},
action: 'http://localhost:8080/vidoe/up',
onChange(info) {
// const status = info.file.status;
console.log(info);
// if (status !== 'uploading') {
// console.log(info.file, info.fileList);
// }
// if (status === 'done') {
// message.success(`${info.file.name} file uploaded successfully.`);
// } else if (status === 'error') {
// message.error(`${info.file.name} file upload failed.`);
// }
},
};
return(
<div>
<Dragger {...props}>
<p className="ant-upload-drag-icon">
<Icon type="inbox" />
</p>
<p className="ant-upload-text">点击或者拖动视频文件到这里</p>
</Dragger>,
</div>
)
}
}
This is the picture I gave the error.
I am sorry, I just learned to use StackOverflow. If my description is not clear, please let me know, this question has been annoying me for a long time, thank you.
This error is a security measure of google chrome. It appears when you use a 2 different servers for front and back end. install this library to fix it:
npm install cors
https://www.npmjs.com/package/cors

Categories