Rename Source Media.fh_lua--[[
@Title: Rename Source Media
@Type: Source-driven data entry
@SubType: all
@Author: Calico Pie
@Version: 1.4
@GH #46 #58 #58-2
@Keywords:
@LastUpdated: September 2020
@Description: Caution: this plugin can potentially rename media files that are external to the current project. If you have multiple Family Historian projects that store links to the same media files,
this might not be what you want.
Like all source-driven data entry plugins, this plugin is designed primarily to be run from the Citation Window when viewing a prepared citation to a Source record.
It is intended to make it easy to ensure consistent naming for associated media. It renames the Media records and usually also the media files that are associated with the Source record or
the prepared citation, so that their names match the Source record title, as closely as possible. It will add a numeric suffix to ensure uniqueness if necessary.
Bear in mind that each media item is represented within Family Historian by a Media record which in turn stores the details of the actual media file. The media file may be kept either within the project folder or
externally (you get asked about this when the media is added to the project). If the media files are kept within the project, the plugin will rename the media files without prompting for confirmation.
However, if the media files are not kept within the project but are external, it will ask for confirmation before renaming them. Be aware that if a media file is used in other projects as well as the current one,
if you rename the media file, links to that media file in the other projects will no longer work, unless and until you repair them.
If this plugin is run from the Plugins Window, there may not be a prepared citation. In that case, it will prompt the user to select the required Source record. In this case, it will not look at media
linked to any citations associated with that Source record, prepared or otherwise.
]]
fhInitialise(7,0,0)
fh = require ("fhUtils")
-------------------------------------------------------
-- Main
-------------------------------------------------------
function main()
local ptrSource
local iSourceMedia, iCitationMedia = 0,0
local pCite = fh.loadPreparedCitation()
if not(pCite) or not(pCite.source) or pCite.source:IsNull() then
-- Running standalone prompt for Source
ptrSource = fhPromptUserForRecordSel('SOUR',1)[1]
else
-- Prepared Citation - tidy citation media as well
local sTitle = cleanTitle(fhGetDisplayText(pCite.source))
iCitationMedia = countMedia(fhGetItemPtr(pCite.ptr,'~.SOUR'),'Cite~ '..sTitle)
ptrSource = pCite.source:Clone()
end
if ptrSource and ptrSource:IsNotNull() then
local sTitle = cleanTitle(fhGetDisplayText(ptrSource))
local mediaFolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')..'\\'
-- Check if total path exceeds 260, assume the media folder is used
local nPathLen = string.len(mediaFolder) + 15
local nTitleLen = string.len(sTitle)
local nMax = 260 - nPathLen
if (nPathLen + nTitleLen) > 260 then
local field = {
{tag="filename", dr="FIELNAME", label="Media Name",type="STRING",value=sTitle, protect=false, maxlength = nMax, minlength = 1}
}
local r = fh.getParam('Edit Filename','The file name exceeds the maximum available length of '..nMax..'. Please shorten the media title', field,{'OK','Cancel'})
if r.ok then
sTitle = r.results.filename
else
return
end
end
iSourceMedia = countMedia(fhGetItemPtr(ptrSource),sTitle)
i = iSourceMedia + iCitationMedia
local sText
if i == 1 then
sText = ('1 media item will be updated')
elseif i == 0 then
sText = ('No media items found')
fhMessageBox(sText,'MB_OK','MB_ICONINFORMATION')
return
else
sText = (i..' media items will be updated')
end
sText = sText.." to\n"..sTitle.."\n\nDo you want to continue?"
if fh.yes(sText) then
i = doMedia(fhGetItemPtr(ptrSource),sTitle)
if iCitationMedia > 0 then
i = doMedia(fhGetItemPtr(pCite.ptr,'~.SOUR'),'Cite~ '..sTitle)
end
end
end
end
function countMedia(ptrBase, sTitle)
local i = 0
ptrMedia = fhGetItemPtr(ptrBase,'~.OBJE')
while ptrMedia and ptrMedia:IsNotNull() do
i = i + 1
ptrMedia:MoveNext('SAME_TAG')
end
return i
end
function doMedia(ptrBase, sTitle)
local i = 0
ptrMedia = fhGetItemPtr(ptrBase,'~.OBJE')
while ptrMedia and ptrMedia:IsNotNull() do
-- print(fhGetDisplayText(ptrMedia))
renameMedia(ptrMedia,sTitle)
i = i + 1
ptrMedia:MoveNext('SAME_TAG')
end
return i
end
function splitFilename(strFilename)
-- Returns the Path, Filename, and Extension as 3 values
return string.match(strFilename, "(.-)([^\\/]-%.?([^%.\\/]*))$")
end
function fileExists(strFileName)
local fileHandle = io.open(strFileName,"r")
if fileHandle ~= nil then
io.close(fileHandle)
return true
else
return false
end
end
function cleanTitle(sTitle)
local tblList = {'\\','/',':','*','?','|','>','<','"'}
for i, v in ipairs(tblList) do
sTitle = sTitle:gsub(v, "~")
end
sTitle = sTitle:gsub("~+", "~")
return sTitle
end
function renameMedia(ptrMedia, sTitle)
local mediaFolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')..'\\'
local root = ''
local sAsk = ' is not located in the Media folder do you still want to rename it?'
local bRename = false
local ptrFile = fhNewItemPtr()
ptrFile:MoveTo(ptrMedia,'~>FILE')
local oldName = fhGetValueAsText(ptrFile)
local path,name,ext = splitFilename(oldName)
if path:sub(1,5) == 'Media' then
root = mediaFolder
bRename = true
end
local i = 0
if bRename or fh.yes(name..sAsk) then
local newName = path..sTitle..'.'..ext
while fileExists(root..newName) do
i = i + 1
newName = path..sTitle..' ('..i..').'..ext
-- print(newName)
end
local bOK,err = os.rename(root..oldName, root..newName)
if bOK then
fhSetValueAsText(ptrFile,newName)
else
fhMessageBox('Unable to rename file to '..root..newName.." it may exceed the maximum length for your version of Windows\n\nThe media title only will be changed")
end
end
-- Update Title of Media Object
ptrFile:MoveTo(ptrFile,'~.TITL')
local sNewTitle
if i > 0 then
sNewTitle = sTitle..' ('..i..')'
else
sNewTitle = sTitle
end
fhSetValueAsText(ptrFile,sNewTitle)
end
main()
--[[
@Title: Rename Source Media
@Type: Source-driven data entry
@SubType: all
@Author: Calico Pie
@Version: 1.4
@GH #46 #58 #58-2
@Keywords:
@LastUpdated: September 2020
@Description: Caution: this plugin can potentially rename media files that are external to the current project. If you have multiple Family Historian projects that store links to the same media files,
this might not be what you want.
Like all source-driven data entry plugins, this plugin is designed primarily to be run from the Citation Window when viewing a prepared citation to a Source record.
It is intended to make it easy to ensure consistent naming for associated media. It renames the Media records and usually also the media files that are associated with the Source record or
the prepared citation, so that their names match the Source record title, as closely as possible. It will add a numeric suffix to ensure uniqueness if necessary.
Bear in mind that each media item is represented within Family Historian by a Media record which in turn stores the details of the actual media file. The media file may be kept either within the project folder or
externally (you get asked about this when the media is added to the project). If the media files are kept within the project, the plugin will rename the media files without prompting for confirmation.
However, if the media files are not kept within the project but are external, it will ask for confirmation before renaming them. Be aware that if a media file is used in other projects as well as the current one,
if you rename the media file, links to that media file in the other projects will no longer work, unless and until you repair them.
If this plugin is run from the Plugins Window, there may not be a prepared citation. In that case, it will prompt the user to select the required Source record. In this case, it will not look at media
linked to any citations associated with that Source record, prepared or otherwise.
]]
fhInitialise(7,0,0)
fh = require ("fhUtils")
-------------------------------------------------------
-- Main
-------------------------------------------------------
function main()
local ptrSource
local iSourceMedia, iCitationMedia = 0,0
local pCite = fh.loadPreparedCitation()
if not(pCite) or not(pCite.source) or pCite.source:IsNull() then
-- Running standalone prompt for Source
ptrSource = fhPromptUserForRecordSel('SOUR',1)[1]
else
-- Prepared Citation - tidy citation media as well
local sTitle = cleanTitle(fhGetDisplayText(pCite.source))
iCitationMedia = countMedia(fhGetItemPtr(pCite.ptr,'~.SOUR'),'Cite~ '..sTitle)
ptrSource = pCite.source:Clone()
end
if ptrSource and ptrSource:IsNotNull() then
local sTitle = cleanTitle(fhGetDisplayText(ptrSource))
local mediaFolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')..'\\'
-- Check if total path exceeds 260, assume the media folder is used
local nPathLen = string.len(mediaFolder) + 15
local nTitleLen = string.len(sTitle)
local nMax = 260 - nPathLen
if (nPathLen + nTitleLen) > 260 then
local field = {
{tag="filename", dr="FIELNAME", label="Media Name",type="STRING",value=sTitle, protect=false, maxlength = nMax, minlength = 1}
}
local r = fh.getParam('Edit Filename','The file name exceeds the maximum available length of '..nMax..'. Please shorten the media title', field,{'OK','Cancel'})
if r.ok then
sTitle = r.results.filename
else
return
end
end
iSourceMedia = countMedia(fhGetItemPtr(ptrSource),sTitle)
i = iSourceMedia + iCitationMedia
local sText
if i == 1 then
sText = ('1 media item will be updated')
elseif i == 0 then
sText = ('No media items found')
fhMessageBox(sText,'MB_OK','MB_ICONINFORMATION')
return
else
sText = (i..' media items will be updated')
end
sText = sText.." to\n"..sTitle.."\n\nDo you want to continue?"
if fh.yes(sText) then
i = doMedia(fhGetItemPtr(ptrSource),sTitle)
if iCitationMedia > 0 then
i = doMedia(fhGetItemPtr(pCite.ptr,'~.SOUR'),'Cite~ '..sTitle)
end
end
end
end
function countMedia(ptrBase, sTitle)
local i = 0
ptrMedia = fhGetItemPtr(ptrBase,'~.OBJE')
while ptrMedia and ptrMedia:IsNotNull() do
i = i + 1
ptrMedia:MoveNext('SAME_TAG')
end
return i
end
function doMedia(ptrBase, sTitle)
local i = 0
ptrMedia = fhGetItemPtr(ptrBase,'~.OBJE')
while ptrMedia and ptrMedia:IsNotNull() do
-- print(fhGetDisplayText(ptrMedia))
renameMedia(ptrMedia,sTitle)
i = i + 1
ptrMedia:MoveNext('SAME_TAG')
end
return i
end
function splitFilename(strFilename)
-- Returns the Path, Filename, and Extension as 3 values
return string.match(strFilename, "(.-)([^\\/]-%.?([^%.\\/]*))$")
end
function fileExists(strFileName)
local fileHandle = io.open(strFileName,"r")
if fileHandle ~= nil then
io.close(fileHandle)
return true
else
return false
end
end
function cleanTitle(sTitle)
local tblList = {'\\','/',':','*','?','|','>','<','"'}
for i, v in ipairs(tblList) do
sTitle = sTitle:gsub(v, "~")
end
sTitle = sTitle:gsub("~+", "~")
return sTitle
end
function renameMedia(ptrMedia, sTitle)
local mediaFolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')..'\\'
local root = ''
local sAsk = ' is not located in the Media folder do you still want to rename it?'
local bRename = false
local ptrFile = fhNewItemPtr()
ptrFile:MoveTo(ptrMedia,'~>FILE')
local oldName = fhGetValueAsText(ptrFile)
local path,name,ext = splitFilename(oldName)
if path:sub(1,5) == 'Media' then
root = mediaFolder
bRename = true
end
local i = 0
if bRename or fh.yes(name..sAsk) then
local newName = path..sTitle..'.'..ext
while fileExists(root..newName) do
i = i + 1
newName = path..sTitle..' ('..i..').'..ext
-- print(newName)
end
local bOK,err = os.rename(root..oldName, root..newName)
if bOK then
fhSetValueAsText(ptrFile,newName)
else
fhMessageBox('Unable to rename file to '..root..newName.." it may exceed the maximum length for your version of Windows\n\nThe media title only will be changed")
end
end
-- Update Title of Media Object
ptrFile:MoveTo(ptrFile,'~.TITL')
local sNewTitle
if i > 0 then
sNewTitle = sTitle..' ('..i..')'
else
sNewTitle = sTitle
end
fhSetValueAsText(ptrFile,sNewTitle)
end
main()Source:Rename-Source-Media-4.fh_lua