summaryrefslogtreecommitdiffstats
path: root/Sluift
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2014-01-19 11:46:51 (GMT)
committerRemko Tronçon <git@el-tramo.be>2014-01-19 16:49:19 (GMT)
commitcbd01a5368f0b761d2032d75c9f7dfde2bf61578 (patch)
tree5016505b1e977e84655cc3bba4435ef7cb80e811 /Sluift
parent4083d6da47ac0e3b77da9c7c222a9439b3e1c04c (diff)
downloadswift-cbd01a5368f0b761d2032d75c9f7dfde2bf61578.zip
swift-cbd01a5368f0b761d2032d75c9f7dfde2bf61578.tar.bz2
Sluift: Add iTunes & PEP User Tune support
Change-Id: I25b3840bb40ce38531922cc737bc82828e026d3f
Diffstat (limited to 'Sluift')
-rw-r--r--Sluift/.gitignore1
-rw-r--r--Sluift/ElementConvertors/ElementConvertors.ipp4
-rw-r--r--Sluift/ElementConvertors/SConscript1
-rw-r--r--Sluift/ElementConvertors/UserTuneConvertor.cpp111
-rw-r--r--Sluift/ElementConvertors/UserTuneConvertor.h29
-rw-r--r--Sluift/Examples/Tunes.lua68
-rw-r--r--Sluift/ITunesInterface.h38
-rw-r--r--Sluift/ITunesInterface.mm58
-rw-r--r--Sluift/Lua/LuaUtils.cpp11
-rw-r--r--Sluift/Lua/LuaUtils.h1
-rw-r--r--Sluift/SConscript11
-rw-r--r--Sluift/SluiftGlobals.h6
-rw-r--r--Sluift/core.lua18
-rw-r--r--Sluift/sluift.cpp39
14 files changed, 392 insertions, 4 deletions
diff --git a/Sluift/.gitignore b/Sluift/.gitignore
index e2d8bbf..4e4c2a4 100644
--- a/Sluift/.gitignore
+++ b/Sluift/.gitignore
@@ -4,5 +4,6 @@ sluift_dll.cpp
sluift
dll.c
core.c
+iTunes.h
dll/
exe/
diff --git a/Sluift/ElementConvertors/ElementConvertors.ipp b/Sluift/ElementConvertors/ElementConvertors.ipp
index b7b9166..da25eb6 100644
--- a/Sluift/ElementConvertors/ElementConvertors.ipp
+++ b/Sluift/ElementConvertors/ElementConvertors.ipp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Remko Tronçon
+ * Copyright (c) 2013-2014 Remko Tronçon
* Licensed under the GNU General Public License.
* See the COPYING file for more information.
*/
@@ -10,6 +10,7 @@
#include <Sluift/ElementConvertors/PubSubItemsConvertor.h>
#include <Sluift/ElementConvertors/PubSubOwnerRedirectConvertor.h>
#include <Sluift/ElementConvertors/PubSubEventRedirectConvertor.h>
+#include <Sluift/ElementConvertors/UserTuneConvertor.h>
#include <Sluift/ElementConvertors/PubSubConfigureConvertor.h>
#include <Sluift/ElementConvertors/PubSubEventDisassociateConvertor.h>
#include <Sluift/ElementConvertors/PubSubOwnerAffiliationsConvertor.h>
@@ -48,6 +49,7 @@ void LuaElementConvertors::registerConvertors() {
convertors.push_back(boost::make_shared<PubSubItemsConvertor>(this));
convertors.push_back(boost::make_shared<PubSubOwnerRedirectConvertor>(this));
convertors.push_back(boost::make_shared<PubSubEventRedirectConvertor>(this));
+ convertors.push_back(boost::make_shared<UserTuneConvertor>(this));
convertors.push_back(boost::make_shared<PubSubConfigureConvertor>(this));
convertors.push_back(boost::make_shared<PubSubEventDisassociateConvertor>(this));
convertors.push_back(boost::make_shared<PubSubOwnerAffiliationsConvertor>(this));
diff --git a/Sluift/ElementConvertors/SConscript b/Sluift/ElementConvertors/SConscript
index e98f7c4..921e325 100644
--- a/Sluift/ElementConvertors/SConscript
+++ b/Sluift/ElementConvertors/SConscript
@@ -8,6 +8,7 @@ convertors = [
env.File("PubSubItemsConvertor.cpp"),
env.File("PubSubOwnerRedirectConvertor.cpp"),
env.File("PubSubEventRedirectConvertor.cpp"),
+ env.File("UserTuneConvertor.cpp"),
env.File("PubSubConfigureConvertor.cpp"),
env.File("PubSubEventDisassociateConvertor.cpp"),
env.File("PubSubOwnerAffiliationsConvertor.cpp"),
diff --git a/Sluift/ElementConvertors/UserTuneConvertor.cpp b/Sluift/ElementConvertors/UserTuneConvertor.cpp
new file mode 100644
index 0000000..22ca94e
--- /dev/null
+++ b/Sluift/ElementConvertors/UserTuneConvertor.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ElementConvertors/UserTuneConvertor.h>
+
+#include <lua.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+
+
+#pragma clang diagnostic ignored "-Wunused-private-field"
+
+using namespace Swift;
+
+UserTuneConvertor::UserTuneConvertor(LuaElementConvertors* convertors) :
+ GenericLuaElementConvertor<UserTune>("user_tune"),
+ convertors(convertors) {
+}
+
+UserTuneConvertor::~UserTuneConvertor() {
+}
+
+boost::shared_ptr<UserTune> UserTuneConvertor::doConvertFromLua(lua_State* L) {
+ boost::shared_ptr<UserTune> result = boost::make_shared<UserTune>();
+ lua_getfield(L, -1, "rating");
+ if (lua_isnumber(L, -1)) {
+ result->setRating(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "title");
+ if (lua_isstring(L, -1)) {
+ result->setTitle(std::string(lua_tostring(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "track");
+ if (lua_isstring(L, -1)) {
+ result->setTrack(std::string(lua_tostring(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "artist");
+ if (lua_isstring(L, -1)) {
+ result->setArtist(std::string(lua_tostring(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "uri");
+ if (lua_isstring(L, -1)) {
+ result->setURI(std::string(lua_tostring(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "source");
+ if (lua_isstring(L, -1)) {
+ result->setSource(std::string(lua_tostring(L, -1)));
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "length");
+ if (lua_isnumber(L, -1)) {
+ result->setLength(boost::numeric_cast<unsigned int>(lua_tonumber(L, -1)));
+ }
+ lua_pop(L, 1);
+ return result;
+}
+
+void UserTuneConvertor::doConvertToLua(lua_State* L, boost::shared_ptr<UserTune> payload) {
+ lua_createtable(L, 0, 0);
+ if (payload->getRating()) {
+ lua_pushnumber(L, (*payload->getRating()));
+ lua_setfield(L, -2, "rating");
+ }
+ if (payload->getTitle()) {
+ lua_pushstring(L, (*payload->getTitle()).c_str());
+ lua_setfield(L, -2, "title");
+ }
+ if (payload->getTrack()) {
+ lua_pushstring(L, (*payload->getTrack()).c_str());
+ lua_setfield(L, -2, "track");
+ }
+ if (payload->getArtist()) {
+ lua_pushstring(L, (*payload->getArtist()).c_str());
+ lua_setfield(L, -2, "artist");
+ }
+ if (payload->getURI()) {
+ lua_pushstring(L, (*payload->getURI()).c_str());
+ lua_setfield(L, -2, "uri");
+ }
+ if (payload->getSource()) {
+ lua_pushstring(L, (*payload->getSource()).c_str());
+ lua_setfield(L, -2, "source");
+ }
+ if (payload->getLength()) {
+ lua_pushnumber(L, (*payload->getLength()));
+ lua_setfield(L, -2, "length");
+ }
+}
+
+boost::optional<LuaElementConvertor::Documentation> UserTuneConvertor::getDocumentation() const {
+ return Documentation(
+ "UserTune",
+ "This table has the following fields:\n\n"
+ "- `rating`: number (Optional)\n"
+ "- `title`: string (Optional)\n"
+ "- `track`: string (Optional)\n"
+ "- `artist`: string (Optional)\n"
+ "- `uri`: string (Optional)\n"
+ "- `source`: string (Optional)\n"
+ "- `length`: number (Optional)\n"
+ );
+}
diff --git a/Sluift/ElementConvertors/UserTuneConvertor.h b/Sluift/ElementConvertors/UserTuneConvertor.h
new file mode 100644
index 0000000..6f95164
--- /dev/null
+++ b/Sluift/ElementConvertors/UserTuneConvertor.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/Override.h>
+
+#include <Sluift/GenericLuaElementConvertor.h>
+#include <Swiften/Elements/UserTune.h>
+
+namespace Swift {
+ class LuaElementConvertors;
+
+ class UserTuneConvertor : public GenericLuaElementConvertor<UserTune> {
+ public:
+ UserTuneConvertor(LuaElementConvertors* convertors);
+ virtual ~UserTuneConvertor();
+
+ virtual boost::shared_ptr<UserTune> doConvertFromLua(lua_State*) SWIFTEN_OVERRIDE;
+ virtual void doConvertToLua(lua_State*, boost::shared_ptr<UserTune>) SWIFTEN_OVERRIDE;
+ virtual boost::optional<Documentation> getDocumentation() const SWIFTEN_OVERRIDE;
+
+ private:
+ LuaElementConvertors* convertors;
+ };
+}
diff --git a/Sluift/Examples/Tunes.lua b/Sluift/Examples/Tunes.lua
new file mode 100644
index 0000000..37ad996
--- /dev/null
+++ b/Sluift/Examples/Tunes.lua
@@ -0,0 +1,68 @@
+--[[
+ Copyright (c) 2014 Remko Tronçon
+ Licensed under the GNU General Public License v3.
+ See Documentation/Licenses/GPLv3.txt for more information.
+--]]
+
+--[[
+
+ Tune Publisher/Listener
+
+ Publishes the currently playing tune in iTunes, and prints
+ the playing tunes of contacts
+
+ The following environment variables are used:
+ - SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+ - SLUIFT_DEBUG: Sets whether debugging should be turned on
+
+--]]
+
+require 'sluift'
+
+sluift.debug = os.getenv('SLUIFT_DEBUG') or false
+
+client = sluift.new_client(os.getenv('SLUIFT_JID'), os.getenv('SLUIFT_PASS'))
+client:connect(function (c)
+ -- Send initial presence (with service discovery information)
+ c:set_caps_node('http://swift.im/Tunes')
+ c:set_disco_info{
+ identities = {{name = 'Tunes'}},
+ features = {
+ sluift.disco.features.DISCO_INFO,
+ sluift.disco.features.USER_TUNE .. '+notify'
+ }}
+ c:send_presence{priority = -1}
+
+ local pubsub = c:pubsub(sluift.jid.to_bare(c:jid()))
+ local tunes_node = pubsub:node(sluift.disco.features.USER_TUNE)
+ local current_track = nil
+ while true do
+ -- Publish currently playing tune
+ if sluift.itunes then
+ local track = sluift.itunes.get_current_track()
+ if track ~= current_track then
+ tunes_node:publish{item = {
+ _type = 'user_tune',
+ title = track.name,
+ artist = track.artist,
+ track = track.track_number,
+ source = track.album,
+ length = track.length,
+ rating = track.rating and track.rating / 10 or nil
+ }}
+ current_track = track
+ end
+ end
+
+ -- Print incoming events for a while
+ for event in c:pubsub_events{timeout = 1000} do
+ if event._type == 'pubsub_event_items'
+ and event.node == sluift.disco.features.USER_TUNE
+ and event.item.title then
+ print(event.from .. ' is playing "'
+ .. (event.item.artist or '<Unknown Artist>') .. ' - '
+ .. event.item.title .. '"')
+ end
+ end
+ end
+end)
diff --git a/Sluift/ITunesInterface.h b/Sluift/ITunesInterface.h
new file mode 100644
index 0000000..c3cccd2
--- /dev/null
+++ b/Sluift/ITunesInterface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/optional/optional_fwd.hpp>
+
+namespace Swift {
+ class SWIFTEN_API ITunesInterface {
+ public:
+ struct Track {
+ std::string name;
+ std::string artist;
+ std::string album;
+ long trackNumber;
+ double duration;
+ long rating;
+ };
+
+ ITunesInterface();
+ virtual ~ITunesInterface();
+
+ boost::optional<Track> getCurrentTrack() const;
+
+ private:
+ bool haveApplication() const;
+
+ private:
+ struct Private;
+ boost::shared_ptr<Private> p;
+ };
+}
diff --git a/Sluift/ITunesInterface.mm b/Sluift/ITunesInterface.mm
new file mode 100644
index 0000000..19c6253
--- /dev/null
+++ b/Sluift/ITunesInterface.mm
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Sluift/ITunesInterface.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfour-char-constants"
+#import <Sluift/iTunes.h>
+#pragma clang diagnostic pop
+#include <ScriptingBridge/ScriptingBridge.h>
+
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/optional.hpp>
+#include <SwifTools/Cocoa/CocoaUtil.h>
+
+using namespace Swift;
+
+struct ITunesInterface::Private {
+ Private() : iTunes(nil) {
+ }
+
+ iTunesApplication* iTunes;
+};
+
+ITunesInterface::ITunesInterface() : p(boost::make_shared<Private>()) {
+}
+
+ITunesInterface::~ITunesInterface() {
+}
+
+boost::optional<ITunesInterface::Track> ITunesInterface::getCurrentTrack() const {
+ if (!haveApplication()) {
+ return boost::optional<ITunesInterface::Track>();
+ }
+ iTunesTrack* currentTrack = p->iTunes.currentTrack;
+ if (!currentTrack) {
+ return boost::optional<ITunesInterface::Track>();
+ }
+ ITunesInterface::Track result;
+ result.name = NS2STDSTRING(currentTrack.name);
+ result.artist = NS2STDSTRING(currentTrack.artist);
+ result.album = NS2STDSTRING(currentTrack.album);
+ result.trackNumber = currentTrack.trackNumber;
+ result.duration = currentTrack.duration;
+ result.rating = currentTrack.rating;
+ return result;
+}
+
+
+bool ITunesInterface::haveApplication() const {
+ if (!p->iTunes) {
+ p->iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
+ }
+ return p->iTunes != nil && [p->iTunes isRunning];
+}
diff --git a/Sluift/Lua/LuaUtils.cpp b/Sluift/Lua/LuaUtils.cpp
index 2192689..915f3cc 100644
--- a/Sluift/Lua/LuaUtils.cpp
+++ b/Sluift/Lua/LuaUtils.cpp
@@ -32,6 +32,17 @@ void Swift::Lua::registerTableToString(lua_State* L, int index) {
lua_pop(L, 1);
}
+void Swift::Lua::registerTableEquals(lua_State* L, int index) {
+ index = Lua::absoluteOffset(L, index);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);
+ lua_getfield(L, -1, "register_table_equals");
+ lua_pushvalue(L, index);
+ if (lua_pcall(L, 1, 0, 0) != 0) {
+ throw Lua::Exception(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+}
+
void Swift::Lua::registerGetByTypeIndex(lua_State* L, int index) {
index = Lua::absoluteOffset(L, index);
lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);
diff --git a/Sluift/Lua/LuaUtils.h b/Sluift/Lua/LuaUtils.h
index 19ab74e..105f249 100644
--- a/Sluift/Lua/LuaUtils.h
+++ b/Sluift/Lua/LuaUtils.h
@@ -23,6 +23,7 @@ namespace Swift {
int convertTableToString(lua_State* L);
void registerTableToString(lua_State* L, int index);
+ void registerTableEquals(lua_State* L, int index);
void registerGetByTypeIndex(lua_State* L, int index);
void registerHelp(lua_State* L, int index,
const std::string& description, const std::string& parameters, const std::string& options);
diff --git a/Sluift/SConscript b/Sluift/SConscript
index c2bbff5..3cc1f29 100644
--- a/Sluift/SConscript
+++ b/Sluift/SConscript
@@ -1,6 +1,6 @@
import Version, os.path
-Import(["env", "conf_env"])
+Import(["env"])
if env["SCONS_STAGE"] == "build" and not GetOption("help") and not env.get("HAVE_LUA", 0) :
print "Warning: Lua was not found. Sluift will not be built."
@@ -42,6 +42,8 @@ elif env["SCONS_STAGE"] == "build" :
]
sluift_sources += env.SConscript("ElementConvertors/SConscript")
+
+
sluift_env = env.Clone()
sluift_env.UseFlags(env.get("LUA_FLAGS", {}))
sluift_env.UseFlags(env["SWIFTEN_FLAGS"])
@@ -51,6 +53,13 @@ elif env["SCONS_STAGE"] == "build" :
if sluift_env["PLATFORM"] == "win32" :
sluift_env.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"])
+ if sluift_env["PLATFORM"] == "darwin" and os.path.isdir("/Applications/iTunes.app") :
+ sluift_env.Append(FRAMEWORKS = ["ScriptingBridge"])
+ sluift_env.Command("iTunes.h", "/Applications/iTunes.app",
+ "sdef ${SOURCE} | sdp -fh --basename iTunes -o ${TARGET.dir}")
+ sluift_env.Append(CPPDEFINES = ["HAVE_ITUNES"])
+ sluift_sources += ["ITunesInterface.mm"]
+
# Generate Version.h
version_header = "#pragma once\n\n"
version_header += "#define SLUIFT_VERSION_STRING \"" + Version.getBuildVersion(env.Dir("#").abspath, "sluift") + "\"\n"
diff --git a/Sluift/SluiftGlobals.h b/Sluift/SluiftGlobals.h
index 5de7cfe..e89f495 100644
--- a/Sluift/SluiftGlobals.h
+++ b/Sluift/SluiftGlobals.h
@@ -9,6 +9,9 @@
#include <Sluift/LuaElementConvertors.h>
#include <Swiften/EventLoop/SimpleEventLoop.h>
#include <Swiften/Network/BoostNetworkFactories.h>
+#ifdef HAVE_ITUNES
+#include <Sluift/ITunesInterface.h>
+#endif
#include <signal.h>
namespace Swift {
@@ -25,5 +28,8 @@ namespace Swift {
int coreLibIndex;
int moduleLibIndex;
sig_atomic_t interruptRequested;
+#ifdef HAVE_ITUNES
+ ITunesInterface iTunes;
+#endif
};
}
diff --git a/Sluift/core.lua b/Sluift/core.lua
index f387354..1969690 100644
--- a/Sluift/core.lua
+++ b/Sluift/core.lua
@@ -72,7 +72,22 @@ local function register_table_tostring(table, print_functions)
metatable.__tostring = table_tostring
end
end
- return table
+end
+
+-- FIXME: Not really a good or efficiant equals, but does the trick for now
+local function table_equals(t1, t2)
+ return tostring(t1) == tostring(t2)
+end
+
+local function register_table_equals(table)
+ if type(table) == 'table' then
+ local metatable = getmetatable(table)
+ if not metatable then
+ metatable = {}
+ setmetatable(table, metatable)
+ end
+ metatable.__eq = table_equals
+ end
end
local function merge_tables(...)
@@ -983,6 +998,7 @@ return {
register_help = register_help,
register_class_help = register_class_help,
register_table_tostring = register_table_tostring,
+ register_table_equals = register_table_equals,
register_get_by_type_index = register_get_by_type_index,
process_pubsub_event = process_pubsub_event,
tprint = tprint,
diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp
index 08ffd92..17990e8 100644
--- a/Sluift/sluift.cpp
+++ b/Sluift/sluift.cpp
@@ -33,6 +33,7 @@
#include <Swiften/IDN/IDNConverter.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Sluift/ITunesInterface.h>
using namespace Swift;
@@ -176,7 +177,6 @@ SLUIFT_LUA_FUNCTION_WITH_HELP(
return 1;
}
-
/*******************************************************************************
* JID Functions
******************************************************************************/
@@ -271,6 +271,34 @@ SLUIFT_LUA_FUNCTION(IDN, stringprep) {
return 1;
}
+/*******************************************************************************
+ * iTunes Functions
+ ******************************************************************************/
+
+#ifdef HAVE_ITUNES
+SLUIFT_LUA_FUNCTION(iTunes, get_current_track) {
+ boost::optional<ITunesInterface::Track> track = Sluift::globals.iTunes.getCurrentTrack();
+ if (!track) {
+ return 0;
+ }
+ lua_createtable(L, 0, 0);
+ lua_pushstring(L, track->artist.c_str());
+ lua_setfield(L, -2, "artist");
+ lua_pushstring(L, track->name.c_str());
+ lua_setfield(L, -2, "name");
+ lua_pushstring(L, track->album.c_str());
+ lua_setfield(L, -2, "album");
+ lua_pushinteger(L, track->trackNumber);
+ lua_setfield(L, -2, "track_number");
+ lua_pushnumber(L, track->duration);
+ lua_setfield(L, -2, "duration");
+ lua_pushinteger(L, track->rating);
+ lua_setfield(L, -2, "rating");
+ Lua::registerTableToString(L, -1);
+ Lua::registerTableEquals(L, -1);
+ return 1;
+}
+#endif
/*******************************************************************************
* Module registration
@@ -296,6 +324,11 @@ SLUIFT_API int luaopen_sluift(lua_State* L) {
lua_call(L, 0, 1);
Sluift::globals.coreLibIndex = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);
+ lua_getfield(L, -1, "Client");
+ lua_setmetatable(L, -3);
+ lua_pop(L, 1);
+
// Register functions
Lua::FunctionRegistry::getInstance().addFunctionsToTable(L, "Sluift");
Lua::FunctionRegistry::getInstance().createFunctionTable(L, "JID");
@@ -304,6 +337,10 @@ SLUIFT_API int luaopen_sluift(lua_State* L) {
lua_setfield(L, -2, "base64");
Lua::FunctionRegistry::getInstance().createFunctionTable(L, "IDN");
lua_setfield(L, -2, "idn");
+#ifdef HAVE_ITUNES
+ Lua::FunctionRegistry::getInstance().createFunctionTable(L, "iTunes");
+ lua_setfield(L, -2, "itunes");
+#endif
// Register convenience functions
lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);