Display Panel (optional)
The Lovense Display Panel makes the show much more interactive compared to simple text based tip activation. We currently provide 2 panels for your tippers/viewers.
- Control Panel - This enables a new tip menu item called Give Control. It automatically generates a control link for the tipper when they tip for this item, allowing models to give direct control of their toys to tippers much more easily.
- Tip Panel - Show the model's tip menu directly on the viewer's page.
⚠️This feature can only be used with Cam Extension or Cam Kit
Step 1: Turn on the Display Panel on your Lovense Developer Dashboard
Go to the developer dashboard and turn on the Display Panel.
You will get a default AES KEY and AES IV that are used for encryption. Use them to encrypt the model name and the tipper name.
Step 2: Import the tipper.js to your tipper's page
<script src="https://api.lovense-api.com/api/cam/tipper/v2/tipper.js"></script>
Step 3: Initialize
Lovense.init(platform, modelKey, tipperKey)
Parameters
Name | Description | Required |
---|---|---|
platform | Your Website Name (shown in the Developer Dashboard) | yes |
modelKey | The model name encrypted on your server side using the AES KEY and AES IV. Do not expose your Key/IV in your JS code. (There is a demo on how to encrypt text using AES in JAVA below) | yes |
tipperKey | The tipper name encrypted using the AES KEY and AES IV (The tipper name should be the Display Name showing in the public broadcasting room) | yes |
⚠️ Display Panels are only available when the model is using Cam Extension version 30.0.8+
If your website is a single page application, when the tipper leaves the model's room, call:
Lovense.destroy()
Here is the demo on how to encrypt text using AES in JAVA:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
public class AESDemo {
private static Key getKey(String key) throws Exception{
byte[] keyBytes = key.getBytes("UTF-8");
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
return newKey;
}
private static AlgorithmParameters getIV(String iv) throws Exception {
byte[] ivs = iv.getBytes("UTF-8");
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(ivs));
return params;
}
public static String encrypt(String key,String iv,String text) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, getKey(key), getIV(iv));
byte[] encryptedBytes = cipher.doFinal(text.getBytes());
return new String(Base64.encodeBase64(encryptedBytes, false,true),"UTF-8");
}
public static String decrypt(String key,String iv,String text) throws Exception {
byte[] textBytes = Base64.decodeBase64(text);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, getKey(key), getIV(iv));
byte[] decodedBytes = cipher.doFinal(textBytes);
return new String(decodedBytes, "UTF-8");
}
public static void main(String[] args) throws Exception{
String key="jHZZwiizsAF2qTAY"; //use your own Key here
String iv="zijknVpNWeeTYGPV"; //use your own IV here
String test="Hello World!";
System.out.println(encrypt(key,iv,test));;
System.out.println(decrypt(key,iv,encrypt(key,iv,test)));;
}
}
Step 4: Data Forwarding
Lovense will notify you when the Model Status has changed, and you should send the Model Status back to the tipper.js. Here is the Flow Chart:
How does it work?
Contact us to provide your callback URL. Lovense will post ModelStatus to your callback URL when necessary (for example, when the model enables/disables features during their broadcast). You forward the ModelStatus
to the tipper/viewer's page and reply to the callback request with "OK". Then call Lovense.recieveData(data)
on the tipper/viewer's page.
Description of the Callback Request
URL: your callback url
Request Protocol: HTTPS Request
Method: POST
Content Type: application/json
the ModelStatus Object::
{
"from":"ABCDxxxxxxxxxxxx", //Encrypted String using your AES KEY and IV
"to": {
"type":"customersOfModel", //which group of people you should forward to
"target":"Lucy,Tony" // users you should forward the data to
},
"data": data // the data you should forward
}
Attributes in ModelStatus
from
[String]: Encrypted string of "Lovense" using your AES KEY. If you can decrypt it with your AES KEY, you can confirm that the data is from Lovense. It is a static string until you changed your AES KEY in Lovense Dashboard.to
[Object]: Whom you should forward the data toto.type
[String]: Which group of people you should forward the data to. Possible values:customersOfModel
,customers
to.target
[String]: Users you should forward to- If the
to.type
iscustomersOfModel
, theto.target
is the model's name (separated with commas if there are multiple values), and you should forward the data to all the customers in the specified model's broadcasting room. - If the
to.type
iscustomer
, theto.target
is the tipper/viewer's screen name (separated with commas if there are multiple values), and you should forward the data to the specified tipper/viewer
- If the
data
[String]: the data that you should forward
Here is a sample written in JAVA for handling the callback from Lovense:
private final String KEY = "Your KEY";
private final String IV = "Your IV";
private final String AESFrom = AESUtil.encrypt("Lovense",KEY,IV);
@RequestMapping(value = "/lovense/callback")
public @ResponseBody String callback(@RequestBody Map<String,Object> modelStatus) {
//1. If from is same as AESFrom
if(AESFrom.equals(modelStatus.get("from"))){
Map<String,String> to = (Map<String, String>) modelStatus.get("to");
String data = (String) modelStatus.get("data");
//2. Handle different target groups
switch (to.get("type")){
case "customersOfModel":
String modelName = to.get("target");
//3.1 TODO forward `data` to the tippers/viewers in the model's room
break;
case "customer":
String customerScreenName = to.get("target");
//TODO forward `data` to the tippers/viewers
break;
default:
break;
}
}
//4. Reply "OK"
return "OK";
}
How to customize toy control panel
If you prefer to bypass the initial step of allowing viewers to choose the control method, you can directly access the control interface by following the method below.
Step 1 To immediately start controlling after receiving a tip, bypass the selection interface
You can achieve this by simply adding a fourth parameter with the value { autoStart: true }
in the initialization function.
Example code:
Lovense.init('platform', 'modelName', 'customerName', { autoStart: true })
Step 2 To customize styles in the developer backend
Example CSS code:
/* hide the remote scan entrance */
.lvs-clink-pl__switch-btn:nth-child(1) {
display: none;
}
/* hide lovense logo */
.lvs-clink-pl__logo-lovense{
display: none;
}
/* change the panel style */
.lvs-clink-pl__inner-content{
background-color: #fff1f0;
}
.lvs-clink-pl__header{
background-color: #ff4d4f;
color: #fff;
}
.lvs-clink-pl__control-l-time{
color: #fff;
}
.lvs-clink-pl__m-t-item{
background-color: #fff;
}
The changes made to custom styles in the developer backend will be immediately visible in the appearance of your panel.