API v1 to API v2 Migration Guide¶
Overview¶
This guide helps you migrate existing Movian plugins from the legacy API v1 to the modern API v2. The migration typically takes 1-4 hours for a standard plugin and provides significant benefits in performance, maintainability, and access to modern features.
Why Migrate?¶
Benefits of API v2¶
- ✅ Better Performance: No emulation layer overhead
- ✅ Modern ECMAScript: Full ES5 support + extensions
- ✅ Module System: Clean, organized code with
require() - ✅ Better Debugging: Clearer stack traces and error messages
- ✅ New Features: Access to APIs not available in v1
- ✅ Future-Proof: Active development and support
- ✅ Best Practices: Follows modern JavaScript patterns
API v1 Limitations¶
- ⚠️ Deprecated: No new features added
- ⚠️ Performance: Emulation layer adds overhead
- ⚠️ Global Pollution: All APIs in global scope
- ⚠️ Limited Features: Cannot access new API v2 capabilities
Quick Start¶
Minimum Changes Required¶
For a basic plugin, you need to:
- Update
plugin.jsonapiversion field - Convert
require()statements to use module paths - Replace
showtime.*calls with module methods - Replace
plugin.*calls with module methods
Example: Minimal Migration¶
Before (API v1):
// plugin.json
{
"apiversion": 1
}
// main.js
var response = showtime.httpGet(url);
plugin.createService("My Service", "myservice:", "video", true);
After (API v2):
// plugin.json
{
"apiversion": 2
}
// main.js
var http = require('movian/http');
var service = require('movian/service');
var response = http.request(url);
service.create("My Service", "myservice:", "video", true);
Step-by-Step Migration¶
Step 1: Update plugin.json¶
Change the apiversion field from 1 to 2:
{
"id": "my-plugin",
"version": "1.0",
"type": "ecmascript",
"apiversion": 2,
"title": "My Plugin"
}
Step 2: Add Module Imports¶
At the top of your main.js, add require() statements for modules you'll use:
// Common modules
var http = require('movian/http');
var service = require('movian/service');
var page = require('movian/page');
var store = require('movian/store');
var settings = require('movian/settings');
// Native modules (as needed)
var popup = require('native/popup');
var string = require('native/string');
var fs = require('native/fs');
Step 3: Replace Global Calls¶
Replace all showtime.* and plugin.* calls with module equivalents.
See Breaking Changes section for complete mapping.
Step 4: Update Plugin Metadata Access¶
API v1:
API v2:
var descriptor = JSON.parse(Plugin.manifest);
var pluginPath = Plugin.path;
var pluginId = Plugin.id;
Step 5: Test Thoroughly¶
- Test all plugin functionality
- Check error handling
- Verify HTTP requests work
- Test settings (if applicable)
- Verify page navigation
- Check service registration
Breaking Changes¶
1. Module System¶
The biggest change is the introduction of CommonJS modules.
API v1 (Global objects):
// Everything available globally
var response = showtime.httpGet(url);
var service = plugin.createService(...);
API v2 (Module system):
// Import modules explicitly
var http = require('movian/http');
var service = require('movian/service');
var response = http.request(url);
service.create(...);
2. HTTP Requests¶
API v1:
API v2:
var http = require('movian/http');
// Simple GET
var response = http.request(url);
// With options
var response = http.request(url, {
args: args,
headers: headers,
method: 'GET'
});
Advanced HTTP:
API v1:
showtime.httpReq(url, {
method: 'POST',
postdata: data,
headers: {'Content-Type': 'application/json'}
}, function(err, response) {
if (err) {
showtime.print("Error: " + err);
} else {
showtime.print("Response: " + response);
}
});
API v2:
var http = require('movian/http');
http.request(url, {
method: 'POST',
postdata: data,
headers: {'Content-Type': 'application/json'}
}, function(err, response) {
if (err) {
console.log("Error:", err);
} else {
console.log("Response:", response);
}
});
3. Service Registration¶
API v1:
var service = plugin.createService(
"My Service",
"myservice:start",
"video",
true,
plugin.path + "icon.png"
);
API v2:
var service = require('movian/service');
service.create(
"My Service",
"myservice:start",
"video",
true,
Plugin.path + "icon.png"
);
4. Page Routes¶
API v1:
plugin.addURI("myservice:start", function(page) {
page.type = "directory";
page.contents = "items";
page.metadata.title = "My Service";
});
API v2:
var page = require('movian/page');
new page.Route("myservice:start", function(page) {
page.type = "directory";
page.contents = "items";
page.metadata.title = "My Service";
});
5. Search Providers¶
API v1:
plugin.addSearcher("My Search", plugin.path + "icon.png", function(page, query) {
// Search implementation
});
API v2:
var page = require('movian/page');
new page.Searcher("My Search", Plugin.path + "icon.png", function(page, query) {
// Search implementation
});
6. Settings¶
API v1:
var settings = plugin.createSettings(
"My Plugin Settings",
plugin.path + "icon.png",
"Configure my plugin"
);
settings.createString("username", "Username", "", function(v) {
// Handle change
});
API v2:
var settings = require('movian/settings');
var s = new settings.globalSettings(
Plugin.id,
"My Plugin Settings",
Plugin.path + "icon.png",
"Configure my plugin"
);
s.createString("username", "Username", "", function(v) {
// Handle change
});
7. Storage/Store¶
API v1:
API v2:
var store = require('movian/store');
var s = store.create("mydata");
s.mykey = "myvalue";
var value = s.mykey;
8. Cache¶
API v1:
// Store in cache
plugin.cachePut("stash", "key", {data: "value"}, 3600);
// Retrieve from cache
var data = plugin.cacheGet("stash", "key");
API v2:
var misc = require('native/misc');
// Store in cache (manual JSON serialization)
misc.cachePut(
'plugin/' + Plugin.id + '/stash',
'key',
JSON.stringify({data: "value"}),
3600
);
// Retrieve from cache
var json = misc.cacheGet('plugin/' + Plugin.id + '/stash', 'key');
var data = json ? JSON.parse(json) : null;
9. String Utilities¶
API v1:
var decoded = showtime.entityDecode(html);
var params = showtime.queryStringSplit(qs);
var escaped = showtime.pathEscape(path);
var duration = showtime.durationToString(seconds);
API v2:
var string = require('native/string');
var decoded = string.entityDecode(html);
var params = string.queryStringSplit(qs);
var escaped = string.pathEscape(path);
var duration = string.durationToString(seconds);
10. Popup Dialogs¶
API v1:
showtime.message("Hello World", true, false);
showtime.notify("Notification", 2);
var text = showtime.textDialog("Enter text:", true);
var creds = plugin.getAuthCredentials("Login Required", "Enter credentials", false);
API v2:
var popup = require('native/popup');
popup.message("Hello World", true, false);
popup.notify("Notification", 2);
var text = popup.textDialog("Enter text:", true);
var creds = popup.getAuthCredentials("Login Required", "Enter credentials", false);
11. Cryptography¶
API v1:
API v2:
var crypto = require('native/crypto');
// MD5
var md5hash = crypto.hashCreate('md5');
crypto.hashUpdate(md5hash, str);
var md5digest = crypto.hashFinalize(md5hash);
var md5hex = Duktape.enc('hex', md5digest);
// SHA1
var sha1hash = crypto.hashCreate('sha1');
crypto.hashUpdate(sha1hash, str);
var sha1digest = crypto.hashFinalize(sha1hash);
var sha1hex = Duktape.enc('hex', sha1digest);
12. File System¶
API v1:
API v2:
13. Logging¶
API v1:
API v2:
console.log("Message");
console.log("Debug message");
// Also available:
console.error("Error message");
console.warn("Warning message");
14. JSON Operations¶
API v1:
API v2:
15. System Information¶
API v1:
var version = showtime.currentVersionString;
var versionInt = showtime.currentVersionInt;
var deviceId = showtime.deviceId;
API v2:
// Global Core object
var version = Core.currentVersionString;
var versionInt = Core.currentVersionInt;
var deviceId = Core.deviceId;
16. Rich Text¶
API v1:
API v2:
var prop = require('movian/prop');
var rt = new prop.RichText("Hello <b>World</b>");
page.metadata.title = rt;
17. Item Hooks¶
API v1:
API v2:
var itemhook = require('movian/itemhook');
itemhook.create({
title: "My Action",
handler: function(item) {
// Handle action
}
});
18. Subtitle Providers¶
API v1:
plugin.addSubtitleProvider(function(req) {
req.addSubtitle(url, title, language, format, source, score);
});
API v2:
var subtitle = require('native/subtitle');
subtitle.addProvider(function(root, query, basescore, autosel) {
subtitle.addItem(root, url, title, language, format, source,
basescore + score, autosel);
}, Plugin.id, Plugin.id);
Complete API Mapping Reference¶
See API Differences for a complete table of all API v1 methods and their API v2 equivalents.
Common Migration Patterns¶
Pattern 1: Simple HTTP GET¶
API v1:
(function(plugin) {
var response = showtime.httpGet("https://api.example.com/data");
var data = showtime.JSONDecode(response);
plugin.addURI("myplugin:start", function(page) {
page.type = "directory";
page.metadata.title = data.title;
});
})(this);
API v2:
var http = require('movian/http');
var page = require('movian/page');
var response = http.request("https://api.example.com/data");
var data = JSON.parse(response);
new page.Route("myplugin:start", function(page) {
page.type = "directory";
page.metadata.title = data.title;
});
Pattern 2: Service with Settings¶
API v1:
(function(plugin) {
var settings = plugin.createSettings("My Plugin", plugin.path + "icon.png");
var username = settings.createString("username", "Username", "");
var service = plugin.createService("My Service", "myservice:", "video", true);
plugin.addURI("myservice:start", function(page) {
showtime.print("Username: " + username.value);
});
})(this);
API v2:
var settings = require('movian/settings');
var service = require('movian/service');
var page = require('movian/page');
var s = new settings.globalSettings(Plugin.id, "My Plugin", Plugin.path + "icon.png");
var username = s.createString("username", "Username", "");
service.create("My Service", "myservice:", "video", true);
new page.Route("myservice:start", function(page) {
console.log("Username:", username.value);
});
Pattern 3: Search with HTTP¶
API v1:
(function(plugin) {
plugin.addSearcher("My Search", plugin.path + "icon.png", function(page, query) {
var url = "https://api.example.com/search?q=" + showtime.paramEscape(query);
var response = showtime.httpGet(url);
var data = showtime.JSONDecode(response);
data.results.forEach(function(item) {
page.appendItem(item.url, "video", {
title: item.title,
description: item.description
});
});
});
})(this);
API v2:
var page = require('movian/page');
var http = require('movian/http');
var string = require('native/string');
new page.Searcher("My Search", Plugin.path + "icon.png", function(page, query) {
var url = "https://api.example.com/search?q=" + string.paramEscape(query);
var response = http.request(url);
var data = JSON.parse(response);
data.results.forEach(function(item) {
page.appendItem(item.url, "video", {
title: item.title,
description: item.description
});
});
});
Pattern 4: Persistent Storage¶
API v1:
(function(plugin) {
var store = plugin.createStore("favorites");
plugin.addURI("myplugin:add", function(page) {
store.favorites = store.favorites || [];
store.favorites.push({id: 123, title: "Item"});
});
plugin.addURI("myplugin:list", function(page) {
var favorites = store.favorites || [];
favorites.forEach(function(item) {
page.appendItem("", "video", {title: item.title});
});
});
})(this);
API v2:
var store = require('movian/store');
var page = require('movian/page');
var s = store.create("favorites");
new page.Route("myplugin:add", function(page) {
s.favorites = s.favorites || [];
s.favorites.push({id: 123, title: "Item"});
});
new page.Route("myplugin:list", function(page) {
var favorites = s.favorites || [];
favorites.forEach(function(item) {
page.appendItem("", "video", {title: item.title});
});
});
Migration Checklist¶
Use this checklist to ensure complete migration:
plugin.json¶
- [ ] Update
"apiversion": 1to"apiversion": 2 - [ ] Verify all other fields are correct
Module Imports¶
- [ ] Add
require()statements for all needed modules - [ ] Remove any old
var plugin = this;patterns - [ ] Organize imports at top of file
Global Object Replacements¶
- [ ] Replace all
showtime.httpGet()withhttp.request() - [ ] Replace all
showtime.httpReq()withhttp.request() - [ ] Replace all
showtime.print()withconsole.log() - [ ] Replace all
showtime.trace()withconsole.log() - [ ] Replace all
showtime.JSONDecode()withJSON.parse() - [ ] Replace all
showtime.JSONEncode()withJSON.stringify() - [ ] Replace all
showtime.entityDecode()withstring.entityDecode() - [ ] Replace all
showtime.queryStringSplit()withstring.queryStringSplit() - [ ] Replace all
showtime.pathEscape()withstring.pathEscape() - [ ] Replace all
showtime.paramEscape()withstring.paramEscape() - [ ] Replace all
showtime.message()withpopup.message() - [ ] Replace all
showtime.notify()withpopup.notify() - [ ] Replace all
showtime.textDialog()withpopup.textDialog() - [ ] Replace all
showtime.md5digest()with crypto module - [ ] Replace all
showtime.sha1digest()with crypto module - [ ] Replace all
showtime.basename()withfs.basename() - [ ] Replace
showtime.currentVersionStringwithCore.currentVersionString - [ ] Replace
showtime.deviceIdwithCore.deviceId
Plugin Object Replacements¶
- [ ] Replace
plugin.createService()withservice.create() - [ ] Replace
plugin.createStore()withstore.create() - [ ] Replace
plugin.addURI()withnew page.Route() - [ ] Replace
plugin.addSearcher()withnew page.Searcher() - [ ] Replace
plugin.createSettings()withnew settings.globalSettings() - [ ] Replace
plugin.cachePut()withmisc.cachePut()+ JSON - [ ] Replace
plugin.cacheGet()withmisc.cacheGet()+ JSON - [ ] Replace
plugin.pathwithPlugin.path - [ ] Replace
plugin.getDescriptor()withJSON.parse(Plugin.manifest) - [ ] Replace
plugin.getAuthCredentials()withpopup.getAuthCredentials() - [ ] Replace
plugin.copyFile()withfs.copyfile() - [ ] Replace
plugin.addItemHook()withitemhook.create() - [ ] Replace
plugin.addSubtitleProvider()withsubtitle.addProvider()
Testing¶
- [ ] Test service registration
- [ ] Test all page routes
- [ ] Test HTTP requests
- [ ] Test settings (if applicable)
- [ ] Test storage/store (if applicable)
- [ ] Test search (if applicable)
- [ ] Test error handling
- [ ] Test with different Movian versions (if possible)
Code Quality¶
- [ ] Remove any unused
require()statements - [ ] Add error handling for HTTP requests
- [ ] Use
console.log()for debugging - [ ] Follow modern JavaScript patterns
- [ ] Add comments for complex logic
Troubleshooting¶
Common Issues¶
Issue: "require is not defined"¶
Cause: Forgot to update apiversion in plugin.json
Solution:
Issue: "showtime is not defined"¶
Cause: Using API v1 syntax with API v2
Solution: Replace with module imports:
Issue: "plugin is not defined"¶
Cause: Using API v1 plugin object with API v2
Solution: Use Plugin (capital P) or module methods:
// Instead of plugin.path
var path = Plugin.path;
// Instead of plugin.createService()
var service = require('movian/service');
service.create(...);
Issue: Cache not working¶
Cause: API v2 requires manual JSON serialization
Solution:
var misc = require('native/misc');
// Store
misc.cachePut('plugin/' + Plugin.id + '/stash', 'key',
JSON.stringify(data), maxage);
// Retrieve
var json = misc.cacheGet('plugin/' + Plugin.id + '/stash', 'key');
var data = json ? JSON.parse(json) : null;
Issue: HTTP requests failing¶
Cause: Different parameter format in API v2
Solution:
var http = require('movian/http');
// API v2 uses options object
var response = http.request(url, {
method: 'GET',
headers: {'User-Agent': 'MyPlugin'},
args: {param: 'value'}
});
Debugging Tips¶
- Use console.log() extensively during migration
- Test incrementally - migrate one function at a time
- Check Movian logs for error messages
- Verify module paths - use
movian/*ornative/* - Test with simple cases first before complex logic
Testing Your Migration¶
Basic Functionality Test¶
var http = require('movian/http');
var service = require('movian/service');
var page = require('movian/page');
console.log("Plugin loaded:", Plugin.id);
console.log("Movian version:", Core.currentVersionString);
service.create("Test Service", "test:start", "video", true);
new page.Route("test:start", function(page) {
console.log("Page opened");
page.type = "directory";
page.metadata.title = "Test Page";
try {
var response = http.request("https://httpbin.org/get");
console.log("HTTP test passed");
} catch(e) {
console.error("HTTP test failed:", e);
}
});
Validation Script¶
Create a test checklist:
var tests = {
"Module loading": function() {
var http = require('movian/http');
return http !== undefined;
},
"Plugin metadata": function() {
return Plugin.id !== undefined && Plugin.path !== undefined;
},
"Core object": function() {
return Core.currentVersionString !== undefined;
},
"Console logging": function() {
console.log("Test");
return true;
},
"JSON operations": function() {
var obj = JSON.parse('{"test": true}');
return obj.test === true;
}
};
for (var name in tests) {
try {
if (tests[name]()) {
console.log("✅", name);
} else {
console.log("❌", name);
}
} catch(e) {
console.log("❌", name, "-", e);
}
}
Performance Considerations¶
API v2 Performance Benefits¶
- No emulation overhead: Direct module calls
- Better memory usage: Modules loaded on demand
- Faster startup: No global object construction
- Optimized runtime: Native Duktape performance
Benchmarking¶
API v1 (with emulation):
var start = Date.now();
for (var i = 0; i < 1000; i++) {
showtime.httpGet(url); // Goes through emulation layer
}
var time = Date.now() - start;
API v2 (native):
var http = require('movian/http');
var start = Date.now();
for (var i = 0; i < 1000; i++) {
http.request(url); // Direct call
}
var time = Date.now() - start;
Typical improvement: 10-30% faster for API-heavy operations.
Best Practices for API v2¶
1. Module Organization¶
// Group related imports
var http = require('movian/http');
var service = require('movian/service');
var page = require('movian/page');
// Native modules separate
var popup = require('native/popup');
var string = require('native/string');
// Constants
var BASE_URL = "https://api.example.com";
var CACHE_TIME = 3600;
// Helper functions
function fetchData(endpoint) {
return http.request(BASE_URL + endpoint);
}
// Main logic
service.create("My Service", "myservice:", "video", true);
2. Error Handling¶
var http = require('movian/http');
var popup = require('native/popup');
new page.Route("myservice:start", function(page) {
try {
var response = http.request(url);
var data = JSON.parse(response);
// Process data...
} catch(e) {
console.error("Error:", e);
popup.notify("Failed to load data: " + e, 2, undefined);
page.error("Failed to load content");
}
});
3. Async Patterns¶
var http = require('movian/http');
// Callback pattern
http.request(url, {}, function(err, response) {
if (err) {
console.error("Error:", err);
return;
}
var data = JSON.parse(response);
// Process data...
});
4. Configuration¶
var settings = require('movian/settings');
var config = new settings.globalSettings(
Plugin.id,
"My Plugin",
Plugin.path + "icon.png"
);
var apiKey = config.createString("apikey", "API Key", "", function(v) {
console.log("API Key updated:", v);
});
// Use in code
function makeRequest() {
if (!apiKey.value) {
popup.notify("Please configure API key in settings", 2);
return;
}
// Make request with apiKey.value...
}
See Also¶
- API Versions - API version overview
- API Differences - Complete API mapping
- Plugin Architecture - Plugin system overview
- API Reference - Complete API v2 documentation
- Best Practices - Plugin development best practices
Source References¶
- API v1 Emulation:
movian/res/ecmascript/legacy/api-v1.js - API Version Constants:
movian/src/ecmascript/ecmascript.h:227 - Runtime Implementation:
movian/src/ecmascript/ecmascript.c
Status: ✅ Ready for Use
Last Updated: 2025-11-08
Movian Version: 4.8+
Accuracy: 🟢 Verified from source code and testing
Need Help?¶
If you encounter issues during migration:
- Check this guide's Troubleshooting section
- Review the API Differences reference
- Examine working plugin examples
- Check Movian logs for error messages
- Test with minimal code first, then add complexity
Migration typically takes 1-4 hours and provides significant long-term benefits!