{"id":1926,"date":"2012-01-17T09:12:18","date_gmt":"2012-01-17T00:12:18","guid":{"rendered":"https:\/\/regex.info\/blog\/2012-01-17\/1926"},"modified":"2012-01-17T09:12:18","modified_gmt":"2012-01-17T00:12:18","slug":"lightroom-plugin-development-adding-a-url-handler-to-a-lightroom-plugin","status":"publish","type":"post","link":"https:\/\/regex.info\/blog\/2012-01-17\/1926","title":{"rendered":"Lightroom Plugin Development: Adding a URL Handler to a Lightroom Plugin"},"content":{"rendered":"\n\n\n<div class='resize_warning' id='arw1926'>\n<b>NOTE<\/b>: Images with an <img class='raw' width='19' height='18' src='\/i\/s\/red_zoomup.gif'\/> icon next to them have been artificially shrunk to better fit your screen; click the icon to restore them, in place, to their regular size.\n<\/div>\n\n\n<p>This post is of interest only to Lightroom plugin developers.<\/p>\n\n<p>Round about <span class='nobr'>Lightroom 3.2,<\/span> Adobe added support for intercepting\n&#8220;<b>lightroom:\/\/<\/b>&#8221; URLs, but have not documented it yet, so I'll do so\nhere. <span class='nobr'>It's particularly<\/span> useful as part of an OAuth-authentication\nprocedure.<\/p>\n\n<p><b>What<\/b><\/p>\n\n<p>You can have your plugin automatically respond to certain\n&#8220;<b>lightroom:\/\/<\/b>&#8221; URLs if they are formatted correctly, and if you\nadd appropriate support to your plugin.<\/p>\n\n<p><b>URL Form<\/b><\/p>\n\n<p>After registering the appropriate handler in you plugin, as described below, the handler will\nbe invoked when your system browser receives <span class='nobr'>a URL<\/span> of the form:<\/p>\n\n<div style='margin-left:3em'>\n   <b>lightroom:\/\/<\/b><i>your.plugin.id<\/i>\n<\/div>\n\n<p>The &#8220;<i>your.plugin.id<\/i>&#8221; is the <b>LrToolkitIdentifier<\/b> in <b>Info.lua<\/b>. For example, the id\nfor <a href='\/blog\/lightroom-goodies\/flickr'>my Flickr plugin<\/a> is\n&#8220;<b>info.regex.lightroom.export.flickr2<\/b>&#8221;, so it can be set to handle URLs such as:<\/p>\n\n<div style='margin-left:3em'>\nlightroom:\/\/info.regex.lightroom.export.flickr2\/blah-blah-blah\n<br\/>lightroom:\/\/info.regex.lightroom.export.flickr2?this=blah&amp;that=blah\n<br\/>lightroom:\/\/info.regex.lightroom.export.flickr2#foobar\n<\/div>\n\n<p>etc.<\/p>\n\n<p><b>How<\/b><\/p>\n\n<p>Create a <b>.lua<\/b> file that returns <span class='nobr'>a table<\/span> along the lines:<\/p>\n<pre style='margin-left:3em; margin-bottom:0'>\nreturn {\n   URLHandler = function(url)\n       -- <i>The url string sometimes actually have a double quote as<\/i>\n       -- <i>the first and last byte, so strip just in case.<\/i>\n       url = url:gsub('^\"(.*)\"$', \"%1\")\n\n       -- <i>Work with url here...<\/i><\/pre><div class='e1925'>.\n<br\/>.\n<br\/>.\n<br\/>.\n<br\/>.\n<\/div><pre style='margin-left:3em;margin-top:10px'>   end\n}\n<\/pre>\n\n<p>Wrapping the function in a one-element table seems like an odd level of indirection, but that's how it works.<\/p>\n\n<p>You then add a reference to that file in your <b>Info.lua<\/b>, as &#8220;<b>URLHandler<\/b>&#8221;. <span class='nobr'>If the file<\/span> is named &#8220;<i>MyUrlHandler.lua<\/i>&#8221;, for example,\nthe reference in <b>Info.lua<\/b> would look like:<\/p>\n\n<style type=\"text\/css\">\n  span.q1925 { font-style: italic; color: #888; size:90% }\n  div.e1925 { color: #888; font-family: \"Times New Roman\"; line-height:50%; margin: 0 0 0 7em }\n<\/style>\n\n<pre style='margin-left:3em; margin-bottom:0'>\nreturn {\n   LrToolkitIdentifier = \"<span class='q1925'>info.regex.lightroom.export.flickr2<\/span>\",\n   LrPluginName        = \"<span class='q1925'>jf Flickr<\/span>\",\n   LrPluginInfoUrl     = \"<span class='q1925'>https:\/\/regex.info\/blog\/lightroom-goodies\/flickr<\/span>\",\n\n   LrSdkVersion        = 3.4,\n   LrSdkMinimumVersion = 3.4,\n<\/pre>\n<div class='e1925'>.\n<br\/>.\n<br\/>.\n<br\/>.\n<br\/>.\n<\/div>\n<pre style='margin-left:3em;margin-top:10px'>\n   <span style='color:white'>URLHandler = \"MyUrlHandler.lua\"<\/span>,\n}\n<\/pre>\n\n<p>Within the URLHandler function, you can access parts of the URL (e.g. in\nan OAuth situation, the token) and stuff into global variables, and perhaps\nshut down <span class='nobr'>a dialog<\/span> that had been open by calling\n\n<span class='nobr'><b>LrDialogs.stopModalWithResult(<\/b>...<b>)<\/b><\/span>.\n\n<\/p>\n\n<p>That last bit seems to be unfortunately necessary... I've found that the\nhandler is not properly invoked in some rare OS\/browser combinations, so <span class='nobr'>I\nfeel<\/span> that to cover all my bases, the plugin must open <span class='nobr'>a dialog<\/span> to tell the\nuser to paste in their token; if the handler ends up working, the plugin\ncan immediately shut down that dialog so the user is not bothered with it.\nUsually, that's exactly what happens, and it happens so quickly that the\nuser never even sees the dialog.<\/p>\n\n<p>I don't think Adobe's plugins do this, so maybe the problem has been\non my end, but <span class='nobr'>I thought<\/span> I'd mention it because this is what my plugins\ndo.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>This post is of interest only to Lightroom plugin developers.<\/p> <p>Round about Lightroom 3.2, Adobe added support for intercepting \"<b>lightroom:\/\/<\/b>\" URLs, but have not documented it yet, so I'll do so here. It's particularly useful as part of an OAuth-authentication procedure.<\/p> <p><b>What<\/b><\/p> <p>You can have your plugin automatically respond to certain \"<b>lightroom:\/\/<\/b>\" URLs if they are formatted correctly, and if you add appropriate support to your plugin.<\/p> <p><b>URL Form<\/b><\/p> <p>After registering the appropriate handler in you plugin, as described below, the handler will be invoked when your system browser receives a URL of the form:<\/p> <p>The \"your.plugin.id\" is the <b>LrToolkitIdentifier<\/b> [...]","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,4],"tags":[],"_links":{"self":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts\/1926"}],"collection":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/comments?post=1926"}],"version-history":[{"count":0,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts\/1926\/revisions"}],"wp:attachment":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/media?parent=1926"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/categories?post=1926"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/tags?post=1926"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}