-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCheck for Unlinked Media.fh_lua
277 lines (258 loc) · 9.76 KB
/
Check for Unlinked Media.fh_lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
--[[
@Title: Check for Unlinked Media
@Author: Jane Taubman
@Version: 1.7
@LastUpdated: January 2013
@Description: Checks all the media files in the media folder are linked to media records the Project and optionally deletes unlinked files.
V1.2 Added options for Moving or just listing files
V1.3 Handles problems where users have the media incorrectly linked to the media folder (e.g using full path names)
V1.4 Correct Issue where Project has special characters in the name,
V1.5 Handle locally linked files with in the Media Folder with out Media Records.
V1.6 Add more robust dirtree function (to handle Mac Directories with invalid windows characters in filenames.
V1.7 Use newer dirtree version
]]
require 'lfs'
function mainfunction()
if fhGetContextInfo('CI_APP_MODE') ~= 'Project Mode' then
fhMessageBox('This Plugin Requires a Project','MB_OK','MB_ICONEXCLAMATION')
return
end
-- Prompt User for Action
local tactions = {'list','delete','move'}
local intButton = iupButtons("Check for Unlinked Media","If using Move or Delete make sure you have a full backup of your Project, \nBEFORE running. \n\nPlease Select from the following options","V","List Unlinked Media","Delete Unlinked Media","Move Unlinked Media")
local action = tactions[intButton]
if action == nil then
return
end
-- Load Media and File Lists
filelist = buildfilelist()
medialist = buildmedialist()
medialist = addlocalmedialist(medialist)
-- Remove Linked files from File List
for k,v in pairs(medialist) do
filelist[k] = nil
end
-- List remaining files
tblOutput,iC = createResultTable()
-- Define Columns
tblOutput.file = {title='File',type='text',width=540,align='align_left',content={}}
for k,v in pairs(filelist) do
-- Add Columns
iC = iC + 1
tblOutput.file.content[iC] = v
end
if iC > 0 then
-- Offer to delete the files
local strTitle = "Files in Media Folder and Not Linked to Project"
if action == 'delete' then
local a = fhMessageBox('Please confirm the delete of the '..iC..' unlinked files\n\n\nWarning This CAN NOT be undone', "MB_YESNO","MB_ICONEXCLAMATION")
if a == "Yes" then
strTitle = "Deleted Files in Media Folder and Not Linked to Project"
deleteFiles(filelist)
fhMessageBox(iC.." Files Deleted")
end
end
if action == 'move' then
dir = getOutPutDir()
if dir ~= nil then
local a = fhMessageBox('Please confirm the move of the '..iC..' unlinked files to\n'..dir..'\n\nWarning This CAN NOT be undone', "MB_YESNO","MB_ICONEXCLAMATION")
if a == "Yes" then
strTitle = "Moved Files in Media Folder to "..dir
copyFiles(filelist,dir)
deleteFiles(filelist,dir)
fhMessageBox(iC.." Files Moved to "..dir)
fhShellExecute(dir)
end
end
end
fhOutputResultSetTitles(strTitle,strTitle, "Date: %#x")
for t in tblOutput() do
fhOutputResultSetColumn(t.title, t.type, t.content, iC, t.width,t.align)
end
else
fhMessageBox('No Unlinked Files Found','MB_OK','MB_ICONINFORMATION')
end
end
-------------------------------------- Custom Functions
function buildfilelist()
local rootfolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')
local mediafolder = rootfolder..'\\media'
local rootpattern = strPlainText(rootfolder)
local filelist = {}
for filename,attr in dirtree(mediafolder) do
if type(attr) == 'table' then
if attr.mode == 'file' then
local strlc = string.lower(filename:gsub(rootpattern..'\\',''))
filelist[strlc] = filename
end
end
end
return filelist
end
function buildmedialist()
local rootfolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')
local mediafolder = rootfolder..'\\Media\\'
mediafolder = strPlainText(mediafolder:lower())
local medialist = {}
local pm = fhNewItemPtr()
for pi in records('OBJE') do
pm:MoveTo(pi,'~._FILE')
local mediaFile = fhGetValueAsText(pm)
local strlc = mediaFile:lower()
-- Trap for Media in the Media folder where people have done the linking wrong
strlc = strlc:gsub(mediafolder,'')
medialist[strlc] = fhGetValueAsText(pm)
end
return medialist
end
function addlocalmedialist(medialist)
local rootfolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')
local mediafolder = rootfolder..'\\Media\\'
mediafolder = strPlainText(mediafolder:lower())
local strItemTag = 'FILE'
local iCount = fhGetRecordTypeCount() -- Get Count of Record types
-- Loop through Record Types
local ii = 0
local ptr = fhNewItemPtr()
for ii =1,iCount do
strRecType = fhGetRecordTypeTag(ii)
ptr:MoveToFirstRecord(strRecType)
while ptr:IsNotNull() do
strPtrTag = fhGetTag(ptr)
if strPtrTag == strItemTag then
local mediaFile = fhGetValueAsText(ptr)
local strlc = mediaFile:lower()
strlc = strlc:gsub(mediafolder,'')
medialist[strlc] = mediaFile
end
ptr:MoveNextSpecial()
end
end
return medialist
end
function deleteFiles(filelist)
for k,v in pairs(filelist) do
os.remove(v)
end
end
function copyFiles(filelist,dir)
local rootfolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER')
local mediafolder = rootfolder..'\\media\\'
for k,v in pairs(filelist) do
local newFile = v:gsub(mediafolder,'')
local newFile = dir..'\\'..newFile:gsub('\\','-')
CopyFile(v,newFile,true)
end
end
function getOutPutDir()
local dir = fhGetContextInfo('CI_PROJECT_PUBLIC_FOLDER')
filedlg = iup.filedlg{dialogtype = "DIR", title = "Please select destination directory", DIRECTORY=dir}
-- Shows file dialog in the center of the screen
filedlg:popup (iup.ANYWHERE, iup.ANYWHERE)
-- Gets file dialog status
status = filedlg.status
if status == "-1" then
iup.Message("IupFileDlg","Operation canceled")
return nil
end
return filedlg.value
end
-------------------------------------- Standard Functions
function strPlainText(strText)
-- Prefix every non-alphanumeric character (%W) with a % escape character, where %% is the % escape, and %1 is original character
return strText:gsub("(%W)","%%%1")
end
function CopyFile(strfromfile,strtofile,bReplace)
if not(bReplace) then
if file_exists(strtofile) then
return false
end
end
local inp = assert(io.open(strfromfile, "rb"))
local out = assert(io.open(strtofile, "wb"))
local data = inp:read("*all")
out:write(data)
assert(inp:close())
assert(out:close())
-- Copy the last modification date and access date from the original.
local attr = lfs.attributes(strfromfile)
lfs.touch(strtofile,attr['modification'],attr['access'])
return true
end
function dirtree(dir)
assert(dir and dir ~= "", "directory parameter is missing or empty")
if string.sub(dir, -1) == "\\" then
dir=string.sub(dir, 1, -2)
end
local function yieldtree(dir)
for entry in lfs.dir(dir) do
if entry ~= "." and entry ~= ".." then
entry=dir.."\\"..entry
local attr=lfs.attributes(entry)
coroutine.yield(entry,attr)
if type(attr)=='table' and attr.mode == "directory" then
yieldtree(entry)
end
end
end
end
return coroutine.wrap(function() yieldtree(dir) end)
end
function records(type)
local pi = fhNewItemPtr()
pi:MoveToFirstRecord(type)
return function ()
p2 = pi:Clone()
pi:MoveNext()
if p2:IsNotNull() then return p2:Clone() end
end
end
function createResultTable()
-- create metatable
local tblOutput_mt = {}
tblOutput_mt.col = 0
tblOutput_mt.seq = {}
tblOutput_mt.__newindex = function (t,k,v)
rawset(t,k,v) -- update original table
local m = getmetatable(t)
m.col = m.col + 1
table.insert(m.seq,k)
end
tblOutput_mt.__call = function (t)
local i = 0
local m = getmetatable(t)
local n = table.getn(m.seq)
return function ()
i = i + 1
if i <= n then return t[m.seq[i]] end
end
end
local tblOutput = {} -- Define Columns Table
setmetatable(tblOutput, tblOutput_mt)
local iC = 0 -- Define count of lines
return tblOutput,iC
end
function iupButtons(strTitle,strMessage,strBoxType,...)
local intButton = 0 -- Returned value if X Close button is used
-- Create the GUI labels and buttons
local lblMessage = iup.label{title=strMessage,expand="YES"}
local lblLineSep = iup.label{separator="HORIZONTAL"}
local iupBox = iup.hbox{homogeneous="YES"}
if strBoxType == "V" then
iupBox = iup.vbox{homogeneous="YES"}
end
for intArgNum, strButton in ipairs(arg) do
local btnName = iup.button{title=strButton,expand="YES",padding="4",action=
function () intButton=intArgNum return iup.CLOSE end
}
iup.Append(iupBox,btnName)
end
-- Create dialogue and turn off resize, maximize, minimize, and menubox except Close button
local dialogue = iup.dialog{title=strTitle,iup.vbox{lblMessage,lblLineSep,iupBox},dialogframe="YES",background="250 250 250",gap="8",margin="8x8"}
dialogue:show()
if (iup.MainLoopLevel()==0) then iup.MainLoop() end
dialogue:destroy()
return intButton
end -- iupButtons
-------------------------------------- Call Main Function
mainfunction()