Add Media URL Shortcut.fh_lua--[[
@Title: Add Media URL Shortcut
@Type: Standard
@Author: Mike Tate
@Contributors:
@Version: 1.3
@Keywords:
@LastUpdated: 26 Nov 2020
@Licence: This plugin is copyright (c) 2020 Mike Tate & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: Add a Media tab link to a Media record for a URL Shortcut to a web page.
@V1.3: FH V7 Lua 3.5 IUP 3.28 compatible version;
@V1.2: Allow the URL to contain Lua magic pattern %n capture index.
@V1.1: Allows a Title name for new Media record.
@V1.0: First published in Plugin Store.
]]
require "iuplua" -- To access GUI window builder
require "lfs" -- To access LUA filing system
function OpenFile(strFileName,strMode) -- Open File and return Handle
local fileHandle, strError = io.open(strFileName,strMode)
if fileHandle == nil then
error("\n Unable to open file in \""..strMode.."\" mode. \n "..strFileName.." \n "..strError.." \n")
end
return fileHandle
end -- function OpenFile
function SaveStringToFile(strString,strFileName) -- Save text string to file
local fileHandle = OpenFile(strFileName,"w")
fileHandle:write(strString)
assert(fileHandle:close())
end -- function SaveStringToFile
function strMakeShortcutFile(strURL) -- Make the URL Shortcut File (.url)
local strShortcut = -- URL Shortcut file template
[[
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=
IDList=
]]
local tblPattern = {} -- Filename encodings for disallowed chars \/:"<>|*?
tblPattern['"'] = "%22"
tblPattern["*"] = "%2A"
tblPattern["/"] = " "
tblPattern[":"] = "%3A"
tblPattern["<"] = "%3C"
tblPattern[">"] = "%3E"
tblPattern["?"] = "%3F"
tblPattern["\\"]= "%5C"
tblPattern["|"] = "%7C"
local strFileName = strURL:gsub("://"," "):gsub('[\\/:"<>|%*%?%.]',tblPattern)..".url"
local strMediaDir = fhGetContextInfo("CI_PROJECT_DATA_FOLDER").."\\Media\\"
local strMediaURL = strMediaDir.."URL\\"
lfs.mkdir(strMediaDir) -- Ensure ...\Media\URL\ folders exist
lfs.mkdir(strMediaURL)
strShortcut = strShortcut:gsub("\t",""):gsub("",function() return strURL end) -- V1.2 fix
SaveStringToFile(strShortcut,strMediaURL..strFileName) -- Might overwrite an existing file
return "Media\\URL\\"..strFileName
end -- function strMakeShortcutFile
function ptrMakeMediaRecord(strURL,strTitl,strFile) -- Make Media record with URL Title linked to Shortcut file
local isOK = false
local ptrObje = fhNewItemPtr()
ptrObje:MoveToFirstRecord("OBJE")
if fhGetAppVersion() < 7 then
while ptrObje:IsNotNull() do -- Check for existing Media record for same Shortcut in GEDCOM 5.5
if fhGetItemText(ptrObje,"~._FILE") == strFile
and fhGetItemText(ptrObje,"~.TITL") == strTitl then
return ptrObje
end
ptrObje:MoveNext()
end
ptrObje = fhCreateItem("OBJE") -- Otherwise create new Media record in GEDCOM 5.5
if ptrObje:IsNotNull() then
for strTag, strVal in pairs ({ _KEYS="URL"; _FILE=strFile; TITL=strTitl; FORM="url"; }) do
local ptrTag = fhCreateItem(strTag,ptrObje,true)
if ptrTag:IsNotNull() then
isOK = fhSetValueAsText(ptrTag,strVal)
if not isOK then break end
end
end
end
else
while ptrObje:IsNotNull() do -- Check for existing Media record for same Shortcut in GEDCOM 5.5.1
if fhGetItemText(ptrObje,"~.FILE") == strFile
and fhGetItemText(ptrObje,"~.FILE.TITL") == strTitl then
return ptrObje
end
ptrObje:MoveNext()
end
ptrObje = fhCreateItem("OBJE") -- Otherwise create new Media record in GEDCOM 5.5.1
if ptrObje:IsNotNull() then
local ptrRoot = ptrObje:Clone()
for _, strData in ipairs ({ "_KEYS:URL"; "FILE:"..strFile; "TITL:"..strTitl; "FORM:url"; }) do
local strTag, strVal = strData:match("^(.+):(.+)$")
local ptrTag = fhCreateItem(strTag,ptrRoot,true)
if ptrTag:IsNotNull() then
isOK = fhSetValueAsText(ptrTag,strVal)
if not isOK then break end
end
if strTag == "FILE" then ptrRoot = ptrTag end
end
end
end
if not isOK then
fhMessageBox("\nFailed to add Media record for URL Shortcut.\n")
ptrObje:SetNull()
end
return ptrObje
end -- function ptrMakeMediaRecord
function ptrLinkMediaRecord(ptrRec,ptrObje) -- Link Media record to Media tab of selected record
local isOK = false
local ptrLink = fhNewItemPtr()
if ptrObje:IsNull() then return ptrLink end
ptrLink:MoveTo(ptrRec,"~.OBJE")
while ptrLink:IsNotNull() do -- Check for existing Media link for same Shortcut
if fhGetValueAsLink(ptrLink):IsSame(ptrObje) then
return ptrLink
end
ptrLink:MoveNext("SAME_TAG")
end
ptrLink = fhCreateItem("OBJE",ptrRec,true) -- Otherwise create new link to Media record
if ptrLink:IsNotNull() then
isOK = fhSetValueAsLink(ptrLink,ptrObje)
end
if not isOK then
fhMessageBox("\nFailed to add Media tab link to Media record.\n")
ptrLink:SetNull()
end
return ptrLink
end -- function ptrLinkMediaRecord
function strGetShortcutURL(strRec,strName) -- Get Shortcut URL via user dialogue
local strHelp = -- Help and Advice message
[[
This adds a web page URL Shortcut to the Media tab of a chosen record.
Enter desired web page URL and Title, then click 'Link Media URL' button.
The Plugin then:
Adds a Shortcut file to the ....fh_data\Media\URL\ folder
Adds a Media record with chosen Title and URL, and Keyword = 'URL'
Adds a link to that Media record in the chosen record Media tab
To open Media URL click the triangular 'Open in Editor/Player' button.
To undo changes use 'Edit > Undo Plugin Updates' before closing FH,
& delete new shortcut files in ....fh_data\Media\URL\ folder.
]]
local strHead = strName.." to Media tab of '"..strRec.."'"
local strURL, strTitl
local function setArg(txtURL,txtTitl) -- Action for btnLink, btnQuit, and Close window
strURL = txtURL
if #strURL < 9 then
strURL = nil
else
strTitl = txtTitl
if strTitl == "" then
strTitl = strURL
end
end
return iup.CLOSE
end -- local function setArg
-- Define IUP controls for user dialogue
local labURL = iup.label { Title="Enter web page URL: "; }
local txtURL = iup.text { Expand="Yes"; Tip="Copy and Paste the URL here (http://...)"; }
local boxURL = iup.hbox { Expand="Yes"; labURL; txtURL; }
local labTitl = iup.label { Title="Enter the media Title:"; }
local txtTitl = iup.text { Expand="Yes"; Tip="If left blank, the Title defaults to URL"; }
local boxTitl = iup.hbox { Expand="Yes"; labTitl; txtTitl; }
local btnLink = iup.button{ Expand="Yes"; Tip="Add Media URL Shortcut"; Title="Link Media URL" ; FgColor="0 128 0"; action=function() return setArg(txtURL.Value,txtTitl.Value) end; }
local btnQuit = iup.button{ Expand="Yes"; Tip="Quit from this Plugin" ; Title="Quit the Plugin"; FgColor="255 0 0"; action=function() return setArg(" ") end; }
local btnHelp = iup.button{ Expand="Yes"; Tip="Obtain Help and Advice"; Title="Help and Advice"; FgColor="0 128 0"; action=function() iup.Message(strName.." ~ Help and Advice",strHelp:gsub("\t","")) end; }
local boxBtn = iup.hbox { Expand="Yes"; btnLink; btnQuit; btnHelp; }
local labUndo = iup.label { Expand="Yes"; Title="Undo changes by using command 'Edit > Undo Plugin Updates' before closing Family Historian"; Alignment="Acenter"; }
local boxAll = iup.vbox { Expand="Yes"; boxURL; boxTitl; boxBtn; labUndo; Homogeneous="Yes"; }
local dialog = iup.dialog{ Title=strHead; boxAll; RasterSize="700x280"; MinSize="700x280"; Padding="4x4"; Gap="9"; Margin="8x8"; MinBox="No"; MaxBox="No"; DefaultEnter=btnLink; DefaultEsc=btnQuit; close_cb=function() return setArg(" ") end; }
dialog:show()
iup.MainLoop()
return strURL, strTitl
end -- function strGetShortcutURL
function MainAction()
local strName = "V1.3 "..fhGetContextInfo("CI_PLUGIN_NAME")
local strMessage = "\nPlease select just one Individual, Family, or Source record.\n"
if fhGetAppVersion() > 5 then -- Cater for FH V6 Unicode and Place records
fhSetStringEncoding("UTF-8")
iup.SetGlobal("UTF8MODE","YES")
iup.SetGlobal("UTF8MODE_FILE","NO")
iup.SetGlobal("CUSTOMQUITMESSAGE","YES") -- Needed for IUP 3.28
strMessage = strMessage:gsub("or Source","Source, or Place")
end
local arrRec = {}
for intTag, strTag in ipairs ({"INDI","FAM","SOUR","_PLAC"}) do
if fhGetAppVersion() > 5 or strTag ~= "_PLAC" then -- Search for selected records
arrRec = fhGetCurrentRecordSel(strTag)
if #arrRec > 0 then break end
end
end
if #arrRec == 1 then -- Just one record selected, so get URL string
local ptrRec = arrRec[1]
local strRec = fhGetDisplayText(ptrRec):gsub("^%.%.%.of ","")
local strURL, strTitl = strGetShortcutURL(strRec,strName) -- Get URL and Title via user dialogue
if strURL then
local strFile = strMakeShortcutFile(strURL) -- Make Shortcut file in \Media\URL\
local ptrObje = ptrMakeMediaRecord(strURL,strTitl,strFile) -- Make Media record for Shortcut
local ptrLink = ptrLinkMediaRecord(ptrRec,ptrObje) -- Link Media tab to Media record
if ptrLink:IsNull() then
error("\n\nPlugin failed to add Media URL.")
end
end
else
fhMessageBox(strName.."\n"..strMessage) -- Zero or more than one record selected
end
end -- function MainAction
if fhGetContextInfo("CI_APP_MODE") == "Project Mode" then
MainAction()
else
fhMessageBox("\nThis Plugin only works for Projects, not standalone Gedcom.\n")
end
--[[
@Title: Add Media URL Shortcut
@Type: Standard
@Author: Mike Tate
@Contributors:
@Version: 1.3
@Keywords:
@LastUpdated: 26 Nov 2020
@Licence: This plugin is copyright (c) 2020 Mike Tate & contributors and is licensed under the MIT License which is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: Add a Media tab link to a Media record for a URL Shortcut to a web page.
@V1.3: FH V7 Lua 3.5 IUP 3.28 compatible version;
@V1.2: Allow the URL to contain Lua magic pattern %n capture index.
@V1.1: Allows a Title name for new Media record.
@V1.0: First published in Plugin Store.
]]
require "iuplua" -- To access GUI window builder
require "lfs" -- To access LUA filing system
function OpenFile(strFileName,strMode) -- Open File and return Handle
local fileHandle, strError = io.open(strFileName,strMode)
if fileHandle == nil then
error("\n Unable to open file in \""..strMode.."\" mode. \n "..strFileName.." \n "..strError.." \n")
end
return fileHandle
end -- function OpenFile
function SaveStringToFile(strString,strFileName) -- Save text string to file
local fileHandle = OpenFile(strFileName,"w")
fileHandle:write(strString)
assert(fileHandle:close())
end -- function SaveStringToFile
function strMakeShortcutFile(strURL) -- Make the URL Shortcut File (.url)
local strShortcut = -- URL Shortcut file template
[[
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=
IDList=
]]
local tblPattern = {} -- Filename encodings for disallowed chars \/:"<>|*?
tblPattern['"'] = "%22"
tblPattern["*"] = "%2A"
tblPattern["/"] = " "
tblPattern[":"] = "%3A"
tblPattern["<"] = "%3C"
tblPattern[">"] = "%3E"
tblPattern["?"] = "%3F"
tblPattern["\\"]= "%5C"
tblPattern["|"] = "%7C"
local strFileName = strURL:gsub("://"," "):gsub('[\\/:"<>|%*%?%.]',tblPattern)..".url"
local strMediaDir = fhGetContextInfo("CI_PROJECT_DATA_FOLDER").."\\Media\\"
local strMediaURL = strMediaDir.."URL\\"
lfs.mkdir(strMediaDir) -- Ensure ...\Media\URL\ folders exist
lfs.mkdir(strMediaURL)
strShortcut = strShortcut:gsub("\t",""):gsub("",function() return strURL end) -- V1.2 fix
SaveStringToFile(strShortcut,strMediaURL..strFileName) -- Might overwrite an existing file
return "Media\\URL\\"..strFileName
end -- function strMakeShortcutFile
function ptrMakeMediaRecord(strURL,strTitl,strFile) -- Make Media record with URL Title linked to Shortcut file
local isOK = false
local ptrObje = fhNewItemPtr()
ptrObje:MoveToFirstRecord("OBJE")
if fhGetAppVersion() < 7 then
while ptrObje:IsNotNull() do -- Check for existing Media record for same Shortcut in GEDCOM 5.5
if fhGetItemText(ptrObje,"~._FILE") == strFile
and fhGetItemText(ptrObje,"~.TITL") == strTitl then
return ptrObje
end
ptrObje:MoveNext()
end
ptrObje = fhCreateItem("OBJE") -- Otherwise create new Media record in GEDCOM 5.5
if ptrObje:IsNotNull() then
for strTag, strVal in pairs ({ _KEYS="URL"; _FILE=strFile; TITL=strTitl; FORM="url"; }) do
local ptrTag = fhCreateItem(strTag,ptrObje,true)
if ptrTag:IsNotNull() then
isOK = fhSetValueAsText(ptrTag,strVal)
if not isOK then break end
end
end
end
else
while ptrObje:IsNotNull() do -- Check for existing Media record for same Shortcut in GEDCOM 5.5.1
if fhGetItemText(ptrObje,"~.FILE") == strFile
and fhGetItemText(ptrObje,"~.FILE.TITL") == strTitl then
return ptrObje
end
ptrObje:MoveNext()
end
ptrObje = fhCreateItem("OBJE") -- Otherwise create new Media record in GEDCOM 5.5.1
if ptrObje:IsNotNull() then
local ptrRoot = ptrObje:Clone()
for _, strData in ipairs ({ "_KEYS:URL"; "FILE:"..strFile; "TITL:"..strTitl; "FORM:url"; }) do
local strTag, strVal = strData:match("^(.+):(.+)$")
local ptrTag = fhCreateItem(strTag,ptrRoot,true)
if ptrTag:IsNotNull() then
isOK = fhSetValueAsText(ptrTag,strVal)
if not isOK then break end
end
if strTag == "FILE" then ptrRoot = ptrTag end
end
end
end
if not isOK then
fhMessageBox("\nFailed to add Media record for URL Shortcut.\n")
ptrObje:SetNull()
end
return ptrObje
end -- function ptrMakeMediaRecord
function ptrLinkMediaRecord(ptrRec,ptrObje) -- Link Media record to Media tab of selected record
local isOK = false
local ptrLink = fhNewItemPtr()
if ptrObje:IsNull() then return ptrLink end
ptrLink:MoveTo(ptrRec,"~.OBJE")
while ptrLink:IsNotNull() do -- Check for existing Media link for same Shortcut
if fhGetValueAsLink(ptrLink):IsSame(ptrObje) then
return ptrLink
end
ptrLink:MoveNext("SAME_TAG")
end
ptrLink = fhCreateItem("OBJE",ptrRec,true) -- Otherwise create new link to Media record
if ptrLink:IsNotNull() then
isOK = fhSetValueAsLink(ptrLink,ptrObje)
end
if not isOK then
fhMessageBox("\nFailed to add Media tab link to Media record.\n")
ptrLink:SetNull()
end
return ptrLink
end -- function ptrLinkMediaRecord
function strGetShortcutURL(strRec,strName) -- Get Shortcut URL via user dialogue
local strHelp = -- Help and Advice message
[[
This adds a web page URL Shortcut to the Media tab of a chosen record.
Enter desired web page URL and Title, then click 'Link Media URL' button.
The Plugin then:
Adds a Shortcut file to the ....fh_data\Media\URL\ folder
Adds a Media record with chosen Title and URL, and Keyword = 'URL'
Adds a link to that Media record in the chosen record Media tab
To open Media URL click the triangular 'Open in Editor/Player' button.
To undo changes use 'Edit > Undo Plugin Updates' before closing FH,
& delete new shortcut files in ....fh_data\Media\URL\ folder.
]]
local strHead = strName.." to Media tab of '"..strRec.."'"
local strURL, strTitl
local function setArg(txtURL,txtTitl) -- Action for btnLink, btnQuit, and Close window
strURL = txtURL
if #strURL < 9 then
strURL = nil
else
strTitl = txtTitl
if strTitl == "" then
strTitl = strURL
end
end
return iup.CLOSE
end -- local function setArg
-- Define IUP controls for user dialogue
local labURL = iup.label { Title="Enter web page URL: "; }
local txtURL = iup.text { Expand="Yes"; Tip="Copy and Paste the URL here (http://...)"; }
local boxURL = iup.hbox { Expand="Yes"; labURL; txtURL; }
local labTitl = iup.label { Title="Enter the media Title:"; }
local txtTitl = iup.text { Expand="Yes"; Tip="If left blank, the Title defaults to URL"; }
local boxTitl = iup.hbox { Expand="Yes"; labTitl; txtTitl; }
local btnLink = iup.button{ Expand="Yes"; Tip="Add Media URL Shortcut"; Title="Link Media URL" ; FgColor="0 128 0"; action=function() return setArg(txtURL.Value,txtTitl.Value) end; }
local btnQuit = iup.button{ Expand="Yes"; Tip="Quit from this Plugin" ; Title="Quit the Plugin"; FgColor="255 0 0"; action=function() return setArg(" ") end; }
local btnHelp = iup.button{ Expand="Yes"; Tip="Obtain Help and Advice"; Title="Help and Advice"; FgColor="0 128 0"; action=function() iup.Message(strName.." ~ Help and Advice",strHelp:gsub("\t","")) end; }
local boxBtn = iup.hbox { Expand="Yes"; btnLink; btnQuit; btnHelp; }
local labUndo = iup.label { Expand="Yes"; Title="Undo changes by using command 'Edit > Undo Plugin Updates' before closing Family Historian"; Alignment="Acenter"; }
local boxAll = iup.vbox { Expand="Yes"; boxURL; boxTitl; boxBtn; labUndo; Homogeneous="Yes"; }
local dialog = iup.dialog{ Title=strHead; boxAll; RasterSize="700x280"; MinSize="700x280"; Padding="4x4"; Gap="9"; Margin="8x8"; MinBox="No"; MaxBox="No"; DefaultEnter=btnLink; DefaultEsc=btnQuit; close_cb=function() return setArg(" ") end; }
dialog:show()
iup.MainLoop()
return strURL, strTitl
end -- function strGetShortcutURL
function MainAction()
local strName = "V1.3 "..fhGetContextInfo("CI_PLUGIN_NAME")
local strMessage = "\nPlease select just one Individual, Family, or Source record.\n"
if fhGetAppVersion() > 5 then -- Cater for FH V6 Unicode and Place records
fhSetStringEncoding("UTF-8")
iup.SetGlobal("UTF8MODE","YES")
iup.SetGlobal("UTF8MODE_FILE","NO")
iup.SetGlobal("CUSTOMQUITMESSAGE","YES") -- Needed for IUP 3.28
strMessage = strMessage:gsub("or Source","Source, or Place")
end
local arrRec = {}
for intTag, strTag in ipairs ({"INDI","FAM","SOUR","_PLAC"}) do
if fhGetAppVersion() > 5 or strTag ~= "_PLAC" then -- Search for selected records
arrRec = fhGetCurrentRecordSel(strTag)
if #arrRec > 0 then break end
end
end
if #arrRec == 1 then -- Just one record selected, so get URL string
local ptrRec = arrRec[1]
local strRec = fhGetDisplayText(ptrRec):gsub("^%.%.%.of ","")
local strURL, strTitl = strGetShortcutURL(strRec,strName) -- Get URL and Title via user dialogue
if strURL then
local strFile = strMakeShortcutFile(strURL) -- Make Shortcut file in \Media\URL\
local ptrObje = ptrMakeMediaRecord(strURL,strTitl,strFile) -- Make Media record for Shortcut
local ptrLink = ptrLinkMediaRecord(ptrRec,ptrObje) -- Link Media tab to Media record
if ptrLink:IsNull() then
error("\n\nPlugin failed to add Media URL.")
end
end
else
fhMessageBox(strName.."\n"..strMessage) -- Zero or more than one record selected
end
end -- function MainAction
if fhGetContextInfo("CI_APP_MODE") == "Project Mode" then
MainAction()
else
fhMessageBox("\nThis Plugin only works for Projects, not standalone Gedcom.\n")
end
Source:Add-Media-URL-Shortcut.fh_lua