Page 1 of 1

New Diskdelete for Windows and Linux [Bugs]

Posted: 10 Dec 2014 13:08
by 147852369
Hello,

my new extension based on this thread: https://forum.videolan.org/viewtopic.php?f=29&t=108811

My extension works so far that it is enough for my needs. But there are some bugs to fix.

Code: Select all

--[[ DISKDELETE for VLC Media Player, Linux and even for Windows! Author of original version (0.2): Mark Morschhäuser http://addons.videolan.org/CONTENT/content-files/153041-Diskdelete.lua Author of this version (1.1): Caglar Yanik Author of playlist functions: Joseph M. Pence ("basaquer") http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 Thanks to mederi @ forum.videolan.org for his advice. ----INSTALLATION (create directories if they don't exist): - put the file in the VLC subdir /lua/extensions, by default: * Windows (all users): %ProgramFiles%\VideoLAN\VLC\lua\extensions\ * Windows (current user): %APPDATA%\VLC\lua\extensions\ * Linux (all users): /usr/share/vlc/lua/extensions/ * Linux (current user): ~/.local/share/vlc/lua/extensions/ * Mac OS X (all users): /Applications/VLC.app/Contents/MacOS/share/lua/extensions/ - Restart VLC. DISKDELETE was developed and tested on Windows 7 x64 and VLC Media Player 2.1.5! ----[REPOSITORY / DEVELOPER] If there is someone who want to develop this extension further, I have a repository for this extension on bitbucket. I can invite you. Falls es jemanden geben sollte, der diese Erweiterung weiter entwickeln möchte, kann sich melden. Ich habe ein Repo auf bitbucket für diese Erweiterung. ----[LICENSE] Copyright (C) 2014 Caglar Yanik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ You use this extension at your own risk - author cannot be held responsible for any direct or indirect damage caused. ----WHAT CAN DISKDELETE DO? This tool helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) by moving selected files to another destination or deleting selected files directly from the hard drive and many more. ----FUNCTIONS: - works on Linux and even Windows! - fast forward to seek into file - skip, skip back - select files for moving or deleting - delete all selected files directly from harddisk or move to another directory - shows sum of filesize (MegaByte) of files to delete - deselect all selected files - export all selected files into a log file - export all selected files into a executable batch file (for Windows) - shift selected files from one list to another - remove all orphaned or duplicate files from playlist - detect OS (Windows or Linux) ---------------------------------------------------------------------- ----WAS KANN DISKDELETE? Diese Erweiterung hilft dir beim schnellen Aussortieren deiner Medienbibliothek (z.B. Bilder, Videos, Audio, Pornos), indem es alle selektierten Dateien entweder in ein anderes Verzeichnis verschiebt oder sie direkt von der Festplatte löscht. ----FUNKTIONEN: - funktioniert auf Linux und sogar auf Windows! - vorspulen - vorspringen / zurückspringen - Dateien zum Löschen oder Verschieben selektieren - alle selektierten Dateien direkt von der Festplatte löschen oder in ein anderes Verzeichnis verschieben - Summe der Dateigrößen in Megabyte der zum Löschen selektierten Dateien anzeigen - alle zum Löschen oder Verschieben selektierten Dateien wieder deselektieren - alle zum Löschen oder Verschieben selektierten Dateien in eine Textdatei exportieren - alle zum Verschieben selektierten Dateien in eine ausführbare Batch-Datei exportieren (für Windows) - selektierte Dateien von einer Liste zur anderen verschieben - alle nicht mehr oder doppelt vorhandenen Dateien aus der Wiedergabeliste löschen - erkennt Betriebssystem (Windows oder Linux) ]] --[[ TO DO, IMPROVEMENTS, BUGS [bug] vlc crashes / stucks sometimes: stucks if DISKDELETE is started before added files into playlist. Have to add files first before start extension [bug] an item must not be in move- and delete-list! Check the another list before add item into list. [improvement] tableContains should check all tables to prevent that one file is in both lists! [improvement] short cuts? [improvement] add gui area for messages output [improvement] show sum of remeaning items in playlist [bug] check file destinations within function for error handling in other functions [improvement] add something like debug.getinfo(1).currentline to errorLogger() [question] use meta_changed to operate? newId ~= currentID [feature] shellFile: if(windows) windows commands else: linux commands [improvement] delete processed (skipped or deleted) items from playlist to not work again from beginning at the end of the playlist [improvement] if 1 item left in playlist, can't delete it because permission denied: solution=> check if 1 item > stop playing, then try to delete in repeat [feature + bug] show sum of files sizes and deleted files [improvement] if duration of a video is very short < 30sec ??? [feature] it's possible that my extension is too overflowed with functions. how about an option between "export mode" and simple mode? [improvement] redesign setOS()? [improvement] check duplicate files at start (activate()) [improvement] try to stop the current playing file first before selectFileForAction, skip, and so on [improvement] main_gui => linux_maingui and windows_maingui => create different GUIs for these OS? [bug] extension is not closable if config is reopened; is running in background after clicking exit [improvement] if logs enabled and user shift items from one list to another, correct log files (undo changes) [feature] skip the first part of video, I don't have to see the first seconds. I always click Fast Forward. [bug] all OS specific functions have to be edited. The important things work on Windows and Linux. ]] --[[ GLOBAL VARIABLES ---------------------------------------------------------]] local program = { deleteList = {}, -- array with files to delete moveList = {}, -- array with files to move detectedOS = '', -- which OS? windows, linux pathSeparator = '' } local counter = { deleted = 0, -- how many files were deleted? moved = 0, -- how many files were moved? sumOfFilesize = 0, -- how much space is freed because of deletion? } function descriptor() return { title = "DISKDELETE 1.1 for Linux and Windows"; shortdesc = "DISKDELETE moves or deletes files from hard disk and many more."; description = "<h1>DISKDELETE<h1>" .. "This extension helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) " .. "by moving selected files to another destination or deleting selected files directly from the hard drive and many more."; version = "1.1"; author = "Caglar Yanik; original version: Mark Morschhäuser"; capabilities = {"input-listener", "meta-listener"} } end function activate() setOS() -- determine OS local p = program.pathSeparator --[[ SETTINGS ---------------------------------------------------------]] config = { durationDivider = 8, -- how fast forward: the smaller the number, the larger the jump. You can jump maximum n-1 times! } -- where to save logs and move files, directories must exist! homedir = vlc.config.homedir() path = { errorLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_ERRORLOG.txt', -- error log moveDestination = "D:\\X\\Downloads\\done\\", -- in which directory to move files moveLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_MOVELOG.txt', -- selected files for moving deleteLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_DELETELOG.txt', -- selected files for deletion shellFileDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_MOVE.' -- batch file with commands and paths to move } if program.detectedOS == 'windows' then path.shellFileDestination = path.shellFileDestination .. "cmd" else path.shellFileDestination = path.shellFileDestination .. "sh" end -- you can delete following four methods if you don't need them vlc.playlist.random("off") -- deactivate random playing vlc.playlist.repeat_("off") -- deactivate repeating playing vlc.playlist.loop("off") -- deactivate repeating playlist vlc.volume.set(0) -- disable audio config_gui() vlc.msg.dbg("[DISKDELETE] activated; " .. collectgarbageCount()) vlc.msg.dbg("[DISKDELETE] setOS: " .. program.detectedOS) end function meta_changed() vlc.msg.dbg("[DISKDELETE] meta_changed; ") return false -- QUESTION: makes sense here? end function input_changed() vlc.msg.dbg("[DISKDELETE] input_changed; " .. collectgarbageCount()) return false end function close() collectgarbage() -- QUESTION: makes sense here? vlc.deactivate() end function deactivate() if(logsEnabled) then moveLog:close() deleteLog:close() errorLog:close() end vlc.msg.dbg("[DISKDELETE] deactivated") end -- first dialog to config settings function config_gui() if(d) then -- TODO: can't get pointer if close extension after reopening config gui d:delete() end d = vlc.dialog("DISKDELETE") h1 = d:add_label("<h3>Config DISKDELETE first</h3><br>", 1, 1, 1, 1) exportLogs = d:add_check_box("ENABLE LOGS?", 3, 1, 1, 1) moveSkippedFile = d:add_check_box("MOVE SKIPPED FILES?", 3, 3, 1, 1) explanation = d:add_html("<b>Enable logs</b> logs to delete and to move files, and error messages in text files.<br><br><b>Move skipped files</b> marks all skipped files for moving.", 1, 4, 3, 1) ok = d:add_button("OK", afterConfig, 3, 7, 1, 1) d:show() end function afterConfig() logsEnabled = exportLogs:get_checked() moveSkippedFilesEnabled = moveSkippedFile:get_checked() vlc.msg.dbg("[DISKDELETE] logsEnabled="..tostring(logsEnabled)) vlc.msg.dbg("[DISKDELETE] moveSkippedFilesEnabled="..tostring(moveSkippedFilesEnabled)) if(logsEnabled) then local mode = "a" moveLog = io.open(path.moveLogDestination, mode) deleteLog = io.open(path.deleteLogDestination, mode) errorLog = io.open(path.errorLogDestination, mode) end -- change gui d:hide() d:del_widget(h1) d:del_widget(exportLogs) d:del_widget(moveSkippedFile) d:del_widget(explanation) d:del_widget(ok) main_gui() end -- creates gui function main_gui() message = d:add_label("", 1, 1, 5, 3) -- previous, next, fast forward, selectFileForDeletion, selectFileForMoving d:add_button("PREVIOUS", toPreviousFile, 1, 3, 1, 1) d:add_button("FAST FORWARD", fastForward, 2, 3, 1, 1) d:add_button("NEXT", skip, 3, 3, 1, 1) d:add_button("SELECT TO DELETE", selectFileForDeletion, 4, 3, 1, 1) d:add_button("SELECT TO MOVE", selectFileForMoving, 5, 3, 1, 1) d:add_button("CONFIG", config_gui, 6, 3, 1, 1) -- TO DELETE d:add_label("<h2>To delete</h2>", 1, 6, 5, 1) d:add_label("<b style=\"color:red;\">All files in this list will be deleted!</b>", 2, 6, 2, 1) d:add_label("DELETED FILES: " .. counter.deleted.. " (" .. counter.sumOfFilesize .. ")", 4, 6, 2, 1) deleteListGUI = d:add_list(1, 7, 10, 10) d:add_button("SHIFT INTO MOVELIST", shiftIntoMoveList, 1, 17) d:add_button("CLEAR LIST", clearDeleteListGUI, 2, 17) d:add_button("REMOVE FROM LIST", removeFromDeleteList, 3, 17) d:add_button("DELETE FILES FROM HARDDISK", deleteFilesInForeach,4, 17) d:add_button("EXPORT DELETE-LIST", exportDeleteList, 5, 17) d:add_label("<hr />", 1, 18, 10, 1) -- TO MOVE d:add_label("<h2>To move</h2>",1, 19, 5, 1) d:add_label("<b style=\"color:red;\">Move destination: " .. path.moveDestination .. "</b>", 2, 19, 5, 1) moveListGUI = d:add_list(1, 20, 10, 10) d:add_button("SHIFT INTO DELETELIST", shiftIntoDeleteList, 1, 30) d:add_button("CLEAR LIST", clearMoveListGUI, 2, 30) d:add_button("REMOVE FROM LIST", removeFromMoveList, 3, 30) if program.detectedOS == "linux" then -- TODO: performance and migration for all OS? d:add_button("MOVE ALL FILES", moveFilesInForeach, 4, 30) d:add_button("EXPORT MOVE-LIST", exportMoveList, 5, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 6, 30) else d:add_button("EXPORT MOVE-LIST", exportMoveList, 4, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 5, 30) end -- have to update GUIList if config_gui was reopened updateGUIList(program.deleteList, deleteListGUI) updateGUIList(program.moveList, moveListGUI) -- FOOTER d:add_label("<div align=\"right\">DISKDELETE by Caglar Yanik, 2014</div>", 1, 31, 6, 1) d:show() end --[[ PLAYLIST OPERATIONS ---------------------------------------------------------]] -- skip to previous file function toPreviousFile() -- TODO: if playlist isn't empty vlc.playlist.prev() vlc.msg.dbg("[DISKDELETE] skip to previous file") end -- skip to next file function skip() -- TODO: check if item is last? if playlist isn't empty! if (moveSkippedFilesEnabled) then selectFileForMoving() -- insert item into moveList else vlc.playlist.next() end collectgarbage() vlc.msg.dbg("[DISKDELETE] skip to next file") end -- fast forward, jumps by durationDivider of duration function fastForward() local input, item, durationInSeconds, durationDividerTotal, currentPosition, formattedDuration input = vlc.object.input() item = vlc.input.item() durationInSeconds = item:duration() - item:duration() % 1 -- instead of math.floor for better perfomance durationDividerTotal = (durationInSeconds / config.durationDivider) - (durationInSeconds / config.durationDivider) % 1 currentPosition = (vlc.var.get(input, "time") - vlc.var.get(input, "time") % 1) if((currentPosition + durationDividerTotal) < durationInSeconds) then vlc.var.set(input, "time", currentPosition + durationDividerTotal) -- fast forward else -- if timeline goes to end skip() end end --[[ LIST FUNCTIONS ---------------------------------------------------------]] -- checks if element is already in table function tableContains(t, element) for k, v in pairs(t) do vlc.msg.dbg("[DISKDELETE] tableContains: k="..k.." v="..v) if v == element then return true end end return false end -- insert current item into list if it isn't already in list function selectFileForAction(list, GUIList, action) if list ~= nil then if (tableContains(list, getFilepath()) == false) then -- if item isn't already in list then insert in list table.insert(list, getFilepath()) updateGUIList(list, GUIList) -- updates the GUI list if(logsEnabled) then if(action == "moving") then moveLog:write(getFilepath().. "\n") -- TODO: \n is Windows style moveLog:flush() elseif(action == "deleting") then deleteLog:write(getFilepath().. "\n") deleteLog:flush() end end vlc.msg.info("[DISKDELETE] select for ".. action .. ": " .. getFilepath()) end vlc.playlist.next() else errorLogger("selectFileForAction(list, GUIList, action): list is nil!") end end -- remove selected items from list function removeFromList(list, GUIList) if list ~= nil then local selected = GUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] removeFromList selected: k=" .. k .. " v=" .. v) if tableContains(list, v) == true then list[k] = nil -- instead of: table.remove(list, k) end end updateGUIList(list,GUIList) else errorLogger("removeFromList(list, GUIList): list is nil!") end end -- shift selected files from one list to another, e.g. from move list to delete list function shiftIntoAnotherList(oldList, newList, oldGUIList, newGUIList) if oldList ~= nil then local selected = oldGUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] shiftIntoAnotherList selected: k=" .. k .. " v=" .. v) if tableContains(oldList, v) == true then oldList[k] = nil table.insert(newList, v) end end updateGUIList(oldList, oldGUIList) updateGUIList(newList,newGUIList) else errorLogger("shiftIntoAnotherList(): oldList is nil!") end end -- clears the list completely function clearList(list, GUIList) for k, v in pairs(list) do -- delete all items in list list[k] = nil end GUIList:clear() collectgarbage() end -- updates GUI list function updateGUIList(list, GUIList) GUIList:clear() for k, v in pairs(list) do GUIList:add_value(v, k) counter.sumOfFilesize = counter.sumOfFilesize + 1 -- for testing, TODO end d:update() end -- exports all list items into a file function exportList(list, destination) -- TODO: check error handling if list ~= nil and destination ~= nil then if list[1] ~= nil then local concat = table.concat(list, "\n") exportInFile(concat, destination) else end else errorLogger("exportList(list, destination): list or destination is nil!") end end --[[ DELETE FUNCTIONS ---------------------------------------------------------]] -- shift selected items from deleteList to moveList function shiftIntoMoveList() shiftIntoAnotherList(program.deleteList, program.moveList, deleteListGUI, moveListGUI) end -- remove selected items from delete-list function removeFromDeleteList() removeFromList(program.deleteList, deleteListGUI) end -- select current file for deletion function selectFileForDeletion() selectFileForAction(program.deleteList, deleteListGUI, "deleting") end -- delete all files in array deleteList function deleteFilesInForeach() for k, v in pairs(program.deleteList) do deleteFile(k) end updateGUIList(program.deleteList, deleteListGUI) updatePlaylist() end -- deletion of one file function deleteFile(_index) if program.deleteList[_index]~=nil then retval, err = os.remove(program.deleteList[_index]) if(retval == nil) then -- error handling; if deletion failed, print why errorLogger( "deleteFile() " .. err) else vlc.msg.info("[DISKDELETE] deleted: " .. program.deleteList[_index]) program.deleteList[_index]=nil counter.deleted = counter.deleted + 1 -- doesn't work end end collectgarbage() end -- exports all deleteList items into a file function exportDeleteList() exportList(program.deleteList, path.deleteLogDestination) end -- clears the list completely function clearDeleteListGUI() clearList(program.deleteList,deleteListGUI) end --[[ MOVE FUNCTIONS ---------------------------------------------------------]] function shiftIntoDeleteList() shiftIntoAnotherList(program.moveList, program.deleteList, moveListGUI, deleteListGUI) end -- remove selected items from move-list function removeFromMoveList() removeFromList(program.moveList, moveListGUI) end -- select current file for moving function selectFileForMoving() selectFileForAction(program.moveList, moveListGUI, "moving") end -- move all selected files function moveFilesInForeach() -- TODO: error handling! -- TODO: table.foreach is deprecated table.foreach(program.moveList,moveFile) updateGUIList(program.moveList, moveListGUI) updatePlaylist() end -- moving of one file function moveFile(_index) if program.moveList[_index] ~= nil then local retStatus = os.execute("MOVE \"" .. program.moveList[_index] .. "\" \"" .. path.moveDestination .. "\"") -- moving!; add " && pause" to this statement for debugging if(retStatus == 1) then -- error handling; if move failed errorLogger("moveFile(): nothing defined") -- TODO else skip() vlc.msg.info("[DISKDELETE] moved: " .. program.moveList[_index] .. " to " .. path.moveDestination) program.moveList[_index]=nil counter.moved = counter.moved + 1 -- TODO: remove also from playlist --updatePlaylist() end end collectgarbage() end -- exports all moveList items into a file function exportMoveList() exportList(program.moveList, path.moveLogDestination) end function createShellFileForMoving() if program.moveList ~= nil then local msg = "" if program.detectedOS == "windows" then -- create batch file msg = "REM " .. os.date() .. "\n" msg = msg .. "MKDIR " .. path.moveDestination .. "\n\n" for k, v in pairs(program.moveList) do msg = msg .. "MOVE \"" .. v .. "\" \"" .. path.moveDestination .. "\"\n" end msg = msg .. "\nPAUSE" elseif program.detectedOS == "linux" then -- create bash file -- TODO: test msg = msg .. "#!/bin/sh\r" msg = msg .. "MKDIR -p ".. path.moveDestination .."\r\r" for k, v in pairs(program.moveList) do msg = msg .. "MV '" .. v .. "' '" .. path.moveDestination .. "'\r" end msg = msg .. "\rpause 'Press [Enter] key to continue...'" else -- end -- TODO: msg can't be nil! => creates shell file although list is empty! if msg ~= nil then exportInFile(msg, path.shellFileDestination) else errorLogger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): msg is nil!") end else errorLogger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): program.moveList is nil!") end end -- clears the list completely function clearMoveListGUI() clearList(program.moveList,moveListGUI) end --[[ PLAYLIST FUNCTIONS ---------------------------------------------------------]] -- source: http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 -- author of original extension: Joseph M. Pence ("basaquer") -- I've modified it for my extension -- TODO: linux migration function updatePlaylist() local fileset = {} for i, v in pairs(vlc.playlist.get("playlist",false).children) do if fileset[v.path] then vlc.msg.dbg("updatePlaylist(): v.path=" .. v.path) vlc.playlist.delete(tonumber(v.id)) else fileset[v.path] = 1 end if check_orphans(v.path)==false then vlc.playlist.delete(tonumber(v.id)) end end end --TODO: linux-migration function check_orphans(filepath) local pathval if program.detectedOS == "windows" then pathval = string.sub(filepath, 9) elseif program.detectedOS == "linux" then pathval = string.sub(filepath, 8) else errorLogger("[DISKDELETE] check_orphans(filepath): not implemented for this OS.") end if pathval==nil then return true end pathval = unescape(pathval) local file,err,code = io.open(pathval, "r") if err and code==2 then return false end end function unescape(str) newstr = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) if newstr==nil then newstr=str end return newstr end --[[ FILE AND OTHER FUNCTIONS ---------------------------------------------------------]] -- TODO: loop if errorLog fails because of exportInFile. function errorLogger(e) e = tostring(e) message:set_text("<b style=\"color:red;\">ERROR:<br />" .. e .. "</b>") vlc.msg.err("[DISKDELETE] error: " .. e .. "; see error log here: " .. path.errorLogDestination) exportInFile(os.date() .. " - " .. e, path.errorLogDestination) end -- check this again function exportInFile(msg, destination, mode) if msg ~= nil and destination ~= nil then msg = tostring(msg) mode = mode or "a" -- standard mode is append local f, err = io.open(destination, mode) if not f then -- error handling vlc.msg.err("exportInFile(): " .. err) else -- file opened f:write(msg .. "\n") f:close() end else vlc.msg.err("exportInFile(msg, destination, mode): msg or destination is nil!") end end -- get current playing file's path, for windows style function getFilepath() -- error handling? if item... or is playing? if playlist empty? local item, uri, filepath item = vlc.input.item() uri = item:uri() -- extract it's URI filepath = vlc.strings.decode_uri(uri) -- decode %foo stuff from the URI if program.detectedOS == "windows" then filepath = string.sub(filepath,9) -- remove 'file://' prefix which is 7 chars long filepath = string.gsub(filepath,"/","\\") -- Windows style path, e.g. c:\mp3\the best.mp3 return filepath elseif program.detectedOS == "linux" then filepath = string.sub(filepath, 8) return filepath else errorLogger("getFilepath(): setOS(): unknown OS") end end -- set OS and path separator function setOS() --if(string.match(os.getenv("UserProfile"), "^C:")) then -- <<< error on linux! if(os.getenv("UserProfile") ~= nil) then program.detectedOS = "windows" program.pathSeparator = "\\" elseif(string.sub(assert(assert(io.popen("uname -s", "r"))):read("*a"),0, -2) == "Linux") then io.close() program.detectedOS = "linux" program.pathSeparator = "/" else program.detectedOS = "unknown" vlc.msg.err("[DISKDELETE] unknown OS") end end -- total memory in use function collectgarbageCount() -- better perfomance since deleting math.ceil() return "collectgarbage(\"count\"):" .. collectgarbage("count") .. " KB" end
The counter doesn't work. And VLC crashes sometimes if I skip the current playing file. Do you have any ideas why? Is it because the last file isn't released before opening the next file?

Sorry for my English.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 28 Dec 2014 00:23
by 147852369
One of the reasons for the stucking of VLC + Extension are corrupt files without information about duration. A simple if-statement / error handling should catch this.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 29 Dec 2014 02:33
by 147852369
Monolog: The counter works now. I have to use widget:set_text(counter.deleted) to replace the old text of the label.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 29 Dec 2014 11:39
by 147852369

Code: Select all

--[[ DISKDELETE for VLC Media Player, Linux and even for Windows! Author of original version (0.2): Mark Morschhäuser http://addons.videolan.org/CONTENT/content-files/153041-Diskdelete.lua Author of this version (1.1): Caglar Yanik Author of playlist functions: Joseph M. Pence ("basaquer") http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 Thanks to mederi @ forum.videolan.org for his advice. ----INSTALLATION (create directories if they don't exist): - put the file in the VLC subdir /lua/extensions, by default: * Windows (all users): %ProgramFiles%\VideoLAN\VLC\lua\extensions\ * Windows (current user): %APPDATA%\VLC\lua\extensions\ * Linux (all users): /usr/share/vlc/lua/extensions/ * Linux (current user): ~/.local/share/vlc/lua/extensions/ * Mac OS X (all users): /Applications/VLC.app/Contents/MacOS/share/lua/extensions/ - Restart VLC. DISKDELETE was developed and tested on Windows 7 x64 and VLC Media Player 2.1.5! ----[REPOSITORY / DEVELOPER] If there is someone who want to develop this extension further, I have a repository for this extension on bitbucket. I can invite you. Falls es jemanden geben sollte, der diese Erweiterung weiter entwickeln möchte, kann sich melden. Ich habe ein Repo auf bitbucket für diese Erweiterung. ----[LICENSE] Copyright (C) 2014 Caglar Yanik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ You use this extension at your own risk - author cannot be held responsible for any direct or indirect damage caused. ----WHAT CAN DISKDELETE DO? This tool helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) by moving selected files to another destination or deleting selected files directly from the hard drive and many more. ----FUNCTIONS: - works on Linux and even Windows! - fast forward to seek into file - skip, skip back - select files for moving or deleting - delete all selected files directly from harddisk or move to another directory - shows sum of filesize (MegaByte) of files to delete - deselect all selected files - export all selected files into a log file - export all selected files into a executable batch file (for Windows) - shift selected files from one list to another - remove all orphaned or duplicate files from playlist - detect OS (Windows or Linux) - hot keys ---------------------------------------------------------------------- ----WAS KANN DISKDELETE? Diese Erweiterung hilft dir beim schnellen Aussortieren deiner Medienbibliothek (z.B. Bilder, Videos, Audio, Pornos), indem es alle selektierten Dateien entweder in ein anderes Verzeichnis verschiebt oder sie direkt von der Festplatte löscht. ----FUNKTIONEN: - funktioniert auf Linux und sogar auf Windows! - vorspulen - vorspringen / zurückspringen - Dateien zum Löschen oder Verschieben selektieren - alle selektierten Dateien direkt von der Festplatte löschen oder in ein anderes Verzeichnis verschieben - Summe der Dateigrößen in Megabyte der zum Löschen selektierten Dateien anzeigen - alle zum Löschen oder Verschieben selektierten Dateien wieder deselektieren - alle zum Löschen oder Verschieben selektierten Dateien in eine Textdatei exportieren - alle zum Verschieben selektierten Dateien in eine ausführbare Batch-Datei exportieren (für Windows) - selektierte Dateien von einer Liste zur anderen verschieben - alle nicht mehr oder doppelt vorhandenen Dateien aus der Wiedergabeliste löschen - erkennt Betriebssystem (Windows oder Linux) - Tastenkürzel ]] --[[ TO DO, IMPROVEMENTS, BUGS [bug] vlc crashes / stucks sometimes: stucks if DISKDELETE is started before added files into playlist. Have to add files first before start extension [bug] an item must not be in move- and delete-list! Check the another list before add item into list. [improvement] tableContains should check all tables to prevent that one file is in both lists! [improvement] short cuts? [improvement] add gui area for messages output [improvement] show sum of remeaning items in playlist [bug] check file destinations within function for error handling in other functions [improvement] add something like debug.getinfo(1).currentline to Logger() [question] use meta_changed to operate? newId ~= currentID [feature] shellFile: if(windows) windows commands else: linux commands [improvement] delete processed (skipped or deleted) items from playlist to not work again from beginning at the end of the playlist [improvement] if 1 item left in playlist, can't delete it because permission denied: solution=> check if 1 item > stop playing, then try to delete in repeat [feature + bug] show sum of files sizes and deleted files [improvement] if duration of a video is very short < 30sec ??? [feature] it's possible that my extension is too overflowed with functions. how about an option between "export mode" and simple mode? [improvement] redesign setOS()? [improvement] check duplicate files at start (activate()) [improvement] try to stop the current playing file first before selectFileForAction, skip, and so on [improvement] main_gui => linux_maingui and windows_maingui => create different GUIs for these OS? [bug] extension is not closable if config is reopened; is running in background after clicking exit [improvement] if logs enabled and user shift items from one list to another, correct log files (undo changes) [feature] skip the first part of video, I don't have to see the first seconds. I always click Fast Forward. [bug] all OS specific functions have to be edited. The important things work on Windows and Linux. [improvement] set everything to local [improvement] counter: select for move, select for delete [feature] simple / export mode? small / big gui? ]] --[[ GLOBAL VARIABLES ---------------------------------------------------------]] local program = { deleteList = {}, -- array with files to delete moveList = {}, -- array with files to move detectedOS = '', -- which OS? windows, linux pathSeparator = '' } local counter = { deleted = 0, -- how many files were deleted? moved = 0, -- how many files were moved? sumOfFilesize = 0, -- how much space is freed because of deletion? } function descriptor() return { title = "DISKDELETE 1.1 for Linux and Windows"; shortdesc = "DISKDELETE moves or deletes files from hard disk and many more."; description = "<h1>DISKDELETE<h1>" .. "This extension helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) " .. "by moving selected files to another destination or deleting selected files directly from the hard drive and many more."; version = "1.1"; author = "Caglar Yanik; original version: Mark Morschhäuser"; capabilities = {"input-listener", "meta-listener"} } end function activate() setOS() -- determine OS local p = program.pathSeparator --[[ SETTINGS ---------------------------------------------------------]] config = { durationDivider = 8, -- how fast forward: the smaller the number, the larger the jump. You can jump maximum n-1 times! } -- where to save logs and move files, directories must exist! homedir = vlc.config.homedir() path = { errorLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_ERRORLOG.txt', -- error log moveDestination = "D:\\X\\Downloads\\done\\", -- in which directory to move files moveLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_MOVELOG.txt', -- selected files for moving deleteLogDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_DELETELOG.txt', -- selected files for deletion shellFileDestination = homedir ..p..'vlc_dev'..p..'VLC_DISKDELETE_MOVE.' -- batch file with commands and paths to move } if program.detectedOS == 'windows' then path.shellFileDestination = path.shellFileDestination .. "cmd" else path.shellFileDestination = path.shellFileDestination .. "sh" end -- you can delete following four methods if you don't need them vlc.playlist.random("off") -- deactivate random playing vlc.playlist.repeat_("off") -- deactivate repeating playing vlc.playlist.loop("off") -- deactivate repeating playlist vlc.volume.set(0) -- disable audio config_gui() vlc.msg.dbg("[DISKDELETE] activated; " .. collectgarbageCount()) vlc.msg.dbg("[DISKDELETE] setOS: " .. program.detectedOS) end function meta_changed() vlc.msg.dbg("[DISKDELETE] meta_changed; ") end function input_changed() vlc.msg.dbg("[DISKDELETE] input_changed; " .. collectgarbageCount()) if (skipFirstPartEnabled) then -- if is true, skip first seconds of video to jump over the intro fastForward() end end function close() collectgarbage() -- QUESTION: makes sense here? vlc.deactivate() end function deactivate() if(logsEnabled) then moveLog:close() deleteLog:close() errorLog:close() end vlc.msg.dbg("[DISKDELETE] deactivated") end -- first dialog to config settings function config_gui() if(d) then -- TODO: can't get pointer if closing extension after reopening config gui d:delete() end d = vlc.dialog("DISKDELETE") h1 = d:add_label("<h3>Config DISKDELETE first</h3><br>", 1, 1, 1, 1) exportLogs = d:add_check_box("ENABLE LOGS?", 3, 1, 1, 1) moveSkippedFile = d:add_check_box("MOVE SKIPPED FILES?", 3, 3, 1, 1) skipFirstPart = d:add_check_box("SKIP FIRST SECONDS?", 3, 5, 1, 1) local explanationHTML = [[ <h2>Explanation of config</h2> <p> <b>Enable logs</b> create log files for moving and deleting files, error messages.<br><br> <b>Move skipped files</b> marks skipped file for moving by clicking [next].<br><br> <b>Skip first seconds</b> skips the beginning / intro of the next playing file. </p> ]] explanation = d:add_html(explanationHTML, 1, 4, 5, 1) ok = d:add_button("OK - Start DISKDELETE", afterConfig, 3, 7, 1, 1) d:show() end function afterConfig() logsEnabled = exportLogs:get_checked() moveSkippedFilesEnabled = moveSkippedFile:get_checked() skipFirstPartEnabled = skipFirstPart:get_checked() vlc.msg.dbg("[DISKDELETE] logsEnabled="..tostring(logsEnabled)) vlc.msg.dbg("[DISKDELETE] moveSkippedFilesEnabled="..tostring(moveSkippedFilesEnabled)) vlc.msg.dbg("[DISKDELETE] skipFirstPart="..tostring(skipFirstPartEnabled)) if(logsEnabled) then moveLog = io.open(path.moveLogDestination, "a") deleteLog = io.open(path.deleteLogDestination, "a") errorLog = io.open(path.errorLogDestination, "a") end -- change gui d:hide() d:del_widget(h1) d:del_widget(exportLogs) d:del_widget(moveSkippedFile) d:del_widget(skipFirstPart) d:del_widget(explanation) d:del_widget(ok) main_gui() end -- creates gui function main_gui() message = d:add_label("", 1, 1, 5, 3) -- previous, next, fast forward, selectFileForDeletion, selectFileForMoving d:add_button("PREVIOUS (Alt+&P)", toPreviousFile, 1, 3, 1, 1) d:add_button("FAST FORWARD (Alt+&F)", fastForward, 2, 3, 1, 1) d:add_button("NEXT (Alt+&N)", skip, 3, 3, 1, 1) d:add_button("SELECT TO DELETE (Alt+&D)", selectFileForDeletion, 4, 3, 1, 1) d:add_button("SELECT TO MOVE (Alt+&M)", selectFileForMoving, 5, 3, 1, 1) d:add_button("CONFIG", config_gui, 6, 3, 1, 1) -- TO DELETE d:add_label("<h2>To delete</h2>", 1, 6, 5, 1) d:add_label("<b style=\"color:red;\">All files in this list will be deleted!</b>", 2, 6, 2, 1) counterLabel = d:add_label("DELETED FILES: " .. counter.deleted.. " (" .. counter.sumOfFilesize .. ")", 4, 6, 2, 1) deleteListGUI = d:add_list(1, 7, 10, 10) d:add_button("SHIFT INTO MOVELIST", shiftIntoMoveList, 1, 17) d:add_button("CLEAR LIST", clearDeleteListGUI, 2, 17) d:add_button("REMOVE FROM LIST", removeFromDeleteList, 3, 17) d:add_button("DELETE FILES FROM HARDDISK", deleteFilesInForeach,4, 17) d:add_button("EXPORT DELETE-LIST", exportDeleteList, 5, 17) d:add_label("<hr />", 1, 18, 10, 1) -- TO MOVE d:add_label("<h2>To move</h2>",1, 19, 5, 1) d:add_label("<b style=\"color:red;\">Move destination: " .. path.moveDestination .. "</b>", 2, 19, 5, 1) moveListGUI = d:add_list(1, 20, 10, 10) d:add_button("SHIFT INTO DELETELIST", shiftIntoDeleteList, 1, 30) d:add_button("CLEAR LIST", clearMoveListGUI, 2, 30) d:add_button("REMOVE FROM LIST", removeFromMoveList, 3, 30) if program.detectedOS == "linux" then -- TODO: performance and migration for all OS? d:add_button("MOVE ALL FILES", moveFilesInForeach, 4, 30) d:add_button("EXPORT MOVE-LIST", exportMoveList, 5, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 6, 30) else d:add_button("EXPORT MOVE-LIST", exportMoveList, 4, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 5, 30) end -- have to update GUIList if config_gui was reopened updateGUIList(program.deleteList, deleteListGUI) updateGUIList(program.moveList, moveListGUI) -- FOOTER d:add_label("<div align=\"right\">DISKDELETE by Caglar Yanik, 2014</div>", 1, 31, 6, 1) d:show() end --[[ PLAYLIST OPERATIONS ---------------------------------------------------------]] -- skip to previous file function toPreviousFile() -- TODO: if playlist isn't empty vlc.playlist.prev() vlc.msg.dbg("[DISKDELETE] skip to previous file") end -- skip to next file function skip() -- TODO: check if item is last? if playlist isn't empty! if (moveSkippedFilesEnabled) then selectFileForMoving() -- insert item into moveList else vlc.playlist.next() end collectgarbage() vlc.msg.dbg("[DISKDELETE] skip to next file") end -- fast forward, jumps by durationDivider of duration function fastForward() local input, item, durationInSeconds, durationDividerTotal, currentPosition, formattedDuration input = vlc.object.input() item = vlc.input.item() if (input:duration() > 0) then -- this should prevent stucking of vlc if duration is unknown durationInSeconds = item:duration() - item:duration() % 1 -- instead of math.floor for better perfomance durationDividerTotal = (durationInSeconds / config.durationDivider) - (durationInSeconds / config.durationDivider) % 1 currentPosition = (vlc.var.get(input, "time") - vlc.var.get(input, "time") % 1) if((currentPosition + durationDividerTotal) < durationInSeconds) then vlc.var.set(input, "time", currentPosition + durationDividerTotal) -- fast forward else -- if timeline goes to end skip() end else Logger("fastForward: duration is less than / equals 0") end end --[[ LIST FUNCTIONS ---------------------------------------------------------]] -- checks if element is already in table function tableContains(t, element) for k, v in pairs(t) do vlc.msg.dbg("[DISKDELETE] tableContains: k="..k.." v="..v) if v == element then return true end end return false end -- insert current item into list if it isn't already in list function selectFileForAction(list, GUIList, action) if list ~= nil then if (tableContains(list, getFilepath()) == false) then -- if item isn't already in list then insert in list table.insert(list, getFilepath()) updateGUIList(list, GUIList) -- updates the GUI list if(logsEnabled) then if(action == "moving") then moveLog:write(getFilepath().. "\n") -- TODO: \n is Windows style moveLog:flush() elseif(action == "deleting") then deleteLog:write(getFilepath().. "\n") deleteLog:flush() end end vlc.msg.info("[DISKDELETE] select for ".. action .. ": " .. getFilepath()) end vlc.playlist.next() else Logger("selectFileForAction(list, GUIList, action): list is nil!") end end -- remove selected items from list function removeFromList(list, GUIList) if list ~= nil then local selected = GUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] removeFromList selected: k=" .. k .. " v=" .. v) if tableContains(list, v) == true then list[k] = nil -- instead of: table.remove(list, k) end end updateGUIList(list,GUIList) else Logger("removeFromList(list, GUIList): list is nil!") end end -- shift selected files from one list to another, e.g. from move list to delete list function shiftIntoAnotherList(oldList, newList, oldGUIList, newGUIList) if oldList ~= nil then local selected = oldGUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] shiftIntoAnotherList selected: k=" .. k .. " v=" .. v) if tableContains(oldList, v) == true then oldList[k] = nil table.insert(newList, v) end end updateGUIList(oldList, oldGUIList) updateGUIList(newList, newGUIList) else Logger("shiftIntoAnotherList(): oldList is nil!") end end -- clears the list completely function clearList(list, GUIList) for k, v in pairs(list) do -- delete all items in list list[k] = nil end GUIList:clear() collectgarbage() end -- updates GUI list function updateGUIList(list, GUIList) GUIList:clear() for k, v in pairs(list) do GUIList:add_value(v, k) end d:update() end -- exports all list items into a file function exportList(list, destination) -- TODO: check error handling if list ~= nil and destination ~= nil then if list[1] ~= nil then local concat = table.concat(list, "\n") exportInFile(concat, destination) else end else Logger("exportList(list, destination): list or destination is nil!") end end --[[ DELETE FUNCTIONS ---------------------------------------------------------]] -- shift selected items from deleteList to moveList function shiftIntoMoveList() shiftIntoAnotherList(program.deleteList, program.moveList, deleteListGUI, moveListGUI) end -- remove selected items from delete-list function removeFromDeleteList() removeFromList(program.deleteList, deleteListGUI) end -- select current file for deletion function selectFileForDeletion() selectFileForAction(program.deleteList, deleteListGUI, "deleting") end -- delete all files in array deleteList function deleteFilesInForeach() for k, v in pairs(program.deleteList) do deleteFile(k) end updateGUIList(program.deleteList, deleteListGUI) counterLabel:set_text("DELETED FILES: " .. counter.deleted.. " (" .. (counter.sumOfFilesize / 1024 / 1024) .. " MB)") updatePlaylist() end -- deletion of one file function deleteFile(_index) if program.deleteList[_index]~=nil then local filesize = fsize(program.deleteList[_index]) local retval, err = os.remove(program.deleteList[_index]) if(retval == nil) then -- error handling; if deletion failed, print why Logger( "deleteFile() " .. err) else vlc.msg.info("[DISKDELETE] deleted: " .. program.deleteList[_index]) counter.deleted = counter.deleted + 1 counter.sumOfFilesize = counter.sumOfFilesize + filesize program.deleteList[_index]=nil end end collectgarbage() end -- exports all deleteList items into a file function exportDeleteList() exportList(program.deleteList, path.deleteLogDestination) end -- clears the list completely function clearDeleteListGUI() clearList(program.deleteList,deleteListGUI) end --[[ MOVE FUNCTIONS ---------------------------------------------------------]] function shiftIntoDeleteList() shiftIntoAnotherList(program.moveList, program.deleteList, moveListGUI, deleteListGUI) end -- remove selected items from move-list function removeFromMoveList() removeFromList(program.moveList, moveListGUI) end -- select current file for moving function selectFileForMoving() selectFileForAction(program.moveList, moveListGUI, "moving") end -- move all selected files function moveFilesInForeach() -- TODO: error handling! -- TODO: table.foreach is deprecated table.foreach(program.moveList,moveFile) updateGUIList(program.moveList, moveListGUI) updatePlaylist() end -- moving of one file function moveFile(_index) if program.moveList[_index] ~= nil then local retStatus = os.execute("MOVE \"" .. program.moveList[_index] .. "\" \"" .. path.moveDestination .. "\"") -- moving!; add " && pause" to this statement for debugging if(retStatus == 1) then -- error handling; if move failed Logger("moveFile(): nothing defined") -- TODO else skip() vlc.msg.info("[DISKDELETE] moved: " .. program.moveList[_index] .. " to " .. path.moveDestination) program.moveList[_index]=nil counter.moved = counter.moved + 1 -- TODO: not in use yet -- TODO: remove also from playlist --updatePlaylist() end end collectgarbage() end -- exports all moveList items into a file function exportMoveList() exportList(program.moveList, path.moveLogDestination) end function createShellFileForMoving() if program.moveList ~= nil then local msg = "" if program.detectedOS == "windows" then -- create batch file msg = "REM " .. os.date() .. "\n" msg = msg .. "MKDIR " .. path.moveDestination .. "\n\n" for k, v in pairs(program.moveList) do msg = msg .. "MOVE \"" .. v .. "\" \"" .. path.moveDestination .. "\"\n" end msg = msg .. "\nPAUSE" elseif program.detectedOS == "linux" then -- create bash file -- TODO: test msg = msg .. "#!/bin/sh\r" msg = msg .. "MKDIR -p ".. path.moveDestination .."\r\r" for k, v in pairs(program.moveList) do msg = msg .. "MV '" .. v .. "' '" .. path.moveDestination .. "'\r" end msg = msg .. "\rpause 'Press [Enter] key to continue...'" else -- end -- TODO: msg can't be nil! => creates shell file although list is empty! if msg ~= nil then exportInFile(msg, path.shellFileDestination) else Logger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): msg is nil!") end else Logger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): program.moveList is nil!") end end -- clears the list completely function clearMoveListGUI() clearList(program.moveList,moveListGUI) end --[[ PLAYLIST FUNCTIONS ---------------------------------------------------------]] -- source: http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 -- author of original extension: Joseph M. Pence ("basaquer") -- I've modified it for my extension -- TODO: linux migration function updatePlaylist() local fileset = {} for i, v in pairs(vlc.playlist.get("playlist",false).children) do if fileset[v.path] then vlc.msg.dbg("updatePlaylist(): v.path=" .. v.path) vlc.playlist.delete(tonumber(v.id)) else fileset[v.path] = 1 end if check_orphans(v.path)==false then vlc.playlist.delete(tonumber(v.id)) end end end --TODO: linux-migration function check_orphans(filepath) local pathval if program.detectedOS == "windows" then pathval = string.sub(filepath, 9) elseif program.detectedOS == "linux" then pathval = string.sub(filepath, 8) else Logger("[DISKDELETE] check_orphans(filepath): not implemented for this OS.") end if pathval==nil then return true end pathval = unescape(pathval) local file,err,code = io.open(pathval, "r") if err and code==2 then return false end end function unescape(str) newstr = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) if newstr==nil then newstr=str end return newstr end --[[ FILE AND OTHER FUNCTIONS ---------------------------------------------------------]] -- TODO: loop if errorLog fails because of exportInFile. function Logger(e) e = tostring(e) message:set_text("<b style=\"color:red;\">ERROR:<br />" .. e .. "</b>") vlc.msg.err("[DISKDELETE] error: " .. e .. "; see error log here: " .. path.errorLogDestination) exportInFile(os.date() .. " - " .. e, path.errorLogDestination) end -- check this again function exportInFile(msg, destination, mode) if msg ~= nil and destination ~= nil then msg = tostring(msg) mode = mode or "a" -- standard mode is append local f, err = io.open(destination, mode) if not f then -- error handling vlc.msg.err("exportInFile(): " .. err) else -- file opened f:write(msg .. "\n") f:close() end else vlc.msg.err("exportInFile(msg, destination, mode): msg or destination is nil!") end end -- get current playing file's path, for windows style function getFilepath() -- error handling? if item... or is playing? if playlist empty? local item, uri, filepath item = vlc.input.item() uri = item:uri() -- extract it's URI filepath = vlc.strings.decode_uri(uri) -- decode %foo stuff from the URI if program.detectedOS == "windows" then filepath = string.sub(filepath,9) -- remove 'file://' prefix which is 7 chars long filepath = string.gsub(filepath,"/","\\") -- Windows style path, e.g. c:\mp3\the best.mp3 return filepath elseif program.detectedOS == "linux" then filepath = string.sub(filepath, 8) return filepath else Logger("getFilepath(): setOS(): unknown OS") end end function fsize(file) local f = io.open(file, "r") local size = f:seek("end") -- get file size f:close() return size end -- set OS and path separator function setOS() --if(string.match(os.getenv("UserProfile"), "^C:")) then -- <<< error on linux! if(os.getenv("UserProfile") ~= nil) then program.detectedOS = "windows" program.pathSeparator = "\\" elseif(string.sub(assert(assert(io.popen("uname -s", "r"))):read("*a"),0, -2) == "Linux") then io.close() program.detectedOS = "linux" program.pathSeparator = "/" else program.detectedOS = "unknown" vlc.msg.err("[DISKDELETE] unknown OS") end end -- total memory in use function collectgarbageCount() -- better perfomance since deleting math.ceil() return "collectgarbage(\"count\"):" .. collectgarbage("count") .. " KB" end
All counters work now. I get this error message: "lua warning: Error while running script C:\Program Files\VideoLAN\VLC\lua\extensions\Diskdelete.lua, function close(): Can't get pointer to dialog"
It's because of the function config_gui, where I delete the dialog if it already exists.

Code: Select all

function config_gui() if(d) then -- TODO: can't get pointer if closing extension after reopening config gui d:delete() end d = vlc.dialog("DISKDELETE")
I could create a helper function, but I want to solve this problem within this one function.

Reproducing:
1. Start extension, see the config_gui
2. click ok to open the main_gui
3. click on the config-button to open the function config_gui again
4. ok
5. close extension
6. extension is uncloseable if I reopened the config.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 30 Dec 2014 22:27
by mederi

Code: Select all

function close() -- collectgarbage() -- QUESTION: makes sense here? vlc.deactivate() end

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 30 Dec 2014 23:42
by 147852369
You're god. I never thought that this would be the cause. Thanks you.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 06 Jan 2015 17:45
by 147852369
A small reporting

Image

I "improved" some parts of the extension. It saves the config now in a config file, so you don't have to edit the directories everytime.

Does someone test this extension? On Windows or Linux? My laptop is too slow for installing virtual maschines. Sorry.
I hope my explanation of the config is understandable.

Code: Select all

--[[ DISKDELETE for VLC Media Player, Linux and even for Windows! Author of original version (0.2): Mark Morschhäuser http://addons.videolan.org/CONTENT/content-files/153041-Diskdelete.lua Author of this version (1.1): Caglar Yanik Author of playlist functions: Joseph M. Pence ("basaquer") http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 Thanks to mederi @ forum.videolan.org for his advice. ----INSTALLATION (create directories if they don't exist): - put the file in the VLC subdir /lua/extensions, by default: * Windows (all users): %ProgramFiles%\VideoLAN\VLC\lua\extensions\ * Windows (current user): %APPDATA%\VLC\lua\extensions\ * Linux (all users): /usr/share/vlc/lua/extensions/ * Linux (current user): ~/.local/share/vlc/lua/extensions/ * Mac OS X (all users): /Applications/VLC.app/Contents/MacOS/share/lua/extensions/ - Restart VLC. DISKDELETE was developed and tested on Windows 7 x64 and VLC Media Player 2.1.5! ----[REPOSITORY / DEVELOPER] If there is someone who want to develop this extension further, I have a repository for this extension on bitbucket. I can invite you. Falls es jemanden geben sollte, der diese Erweiterung weiter entwickeln möchte, kann sich melden. Ich habe ein Repo auf bitbucket für diese Erweiterung. ----[LICENSE] Copyright (C) 2014 Caglar Yanik This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ You use this extension at your own risk - author cannot be held responsible for any direct or indirect damage caused. ----WHAT CAN DISKDELETE DO? This tool helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) by moving selected files to another destination or deleting selected files directly from the hard drive and many more. ----FUNCTIONS: - works on Linux and even Windows! - fast forward to seek into file - skip, skip back - select files for moving or deleting - delete all selected files directly from harddisk or move to another directory - shows sum of filesize (MegaByte) of files to delete - deselect all selected files - export all selected files into a log file - export all selected files into a executable batch file (for Windows) - shift selected files from one list to another - remove all orphaned or duplicate files from playlist - hot keys - saves config ---------------------------------------------------------------------- ----WAS KANN DISKDELETE? Diese Erweiterung hilft dir beim schnellen Aussortieren deiner Medienbibliothek (z.B. Bilder, Videos, Audio, Pornos), indem es alle selektierten Dateien entweder in ein anderes Verzeichnis verschiebt oder sie direkt von der Festplatte löscht. ----FUNKTIONEN: - funktioniert auf Linux und sogar auf Windows! - vorspulen - vorspringen / zurückspringen - Dateien zum Löschen oder Verschieben selektieren - alle selektierten Dateien direkt von der Festplatte löschen oder in ein anderes Verzeichnis verschieben - Summe der Dateigrößen in Megabyte der zum Löschen selektierten Dateien anzeigen - alle zum Löschen oder Verschieben selektierten Dateien wieder deselektieren - alle zum Löschen oder Verschieben selektierten Dateien in eine Textdatei exportieren - alle zum Verschieben selektierten Dateien in eine ausführbare Batch-Datei exportieren (für Windows) - selektierte Dateien von einer Liste zur anderen verschieben - alle nicht mehr oder doppelt vorhandenen Dateien aus der Wiedergabeliste löschen - Tastenkürzel - speichert Konfiguration ]] --[[ TO DO, IMPROVEMENTS, BUGS [bug] vlc crashes / stucks sometimes: stucks if DISKDELETE is started before added files into playlist. Have to add files first before start extension [bug] an item must not be in move- and delete-list! Check the another list before add item into list. [improvement] tableContains should check all tables to prevent that one file is in both lists! [improvement] show sum of remaining items in playlist [bug] check file destinations within function for error handling in other functions [improvement] add something like debug.getinfo(1).currentline to Logger() [question] use meta_changed to operate? newId ~= currentID [feature] shellFile: if(windows) windows commands else: linux commands [improvement] delete processed (skipped or deleted) items from playlist to not work again from beginning at the end of the playlist [feature] it's possible that my extension is too overflowed with functions. how about an option between "export mode" and simple mode? [improvement] if 1 item left in playlist, can't delete it because permission denied: solution=> check if 1 item > stop playing, then try to delete in repeat [improvement] try to stop the current playing file first before selectFileForAction, skip, and so on [improvement] main_gui => linux_maingui and windows_maingui => create different GUIs for these OS? [bug] extension is not closable if config is reopened; is running in background after clicking exit [improvement] if logs enabled and user shift items from one list to another, correct log files (undo changes) [bug] all OS specific functions have to be checked and edited. The important things work on Windows and Linux. [improvement] set everything to local [improvement] counter: select for move, select for delete (GUILists) [improvement] check paths ]] local program = { deleteList = {}, -- array with files to delete moveList = {}, -- array with files to move detectedOS = '', -- which OS? windows or linux | will be detected in setOS() pathSeparator = '', -- os-dependent path separator, will be detected in setOS() durationDivider = 8 -- how fast forward: the smaller the number, the larger the jump. You can jump maximum n-1 times! } local counter = { deleted = 0, -- how many files were deleted? moved = 0, -- how many files were moved? sumOfFilesize = 0, -- how much space is freed because of deletion? } function descriptor() return { title = "DISKDELETE 1.1 for Linux and Windows"; shortdesc = "DISKDELETE moves or deletes files from hard disk and many more."; description = "<h1>DISKDELETE<h1>" .. "This extension helps you in quickly sorting your media library (e.g. pics, videos, audio, porns) " .. "by moving selected files to another destination or deleting selected files directly from the hard drive and many more."; version = "1.1"; author = "Caglar Yanik; original version: Mark Morschhäuser"; capabilities = {"input-listener", "meta-listener"} } end function activate() setOS() -- determine OS: linux or windows, sets program.pathSeparator p = program.pathSeparator --[[ SETTINGS ---------------------------------------------------------]] -- you can delete following four methods if you don't need them vlc.playlist.random("off") -- deactivate random playing vlc.playlist.repeat_("off") -- deactivate repeating playing vlc.playlist.loop("off") -- deactivate repeating playlist vlc.volume.set(0) -- disable audio basedir = vlc.config.homedir() -- default homedir setPaths() -- set all paths for log / config files config_gui() -- show config_gui first vlc.msg.dbg("[DISKDELETE] activated; " .. collectgarbageCount()) vlc.msg.dbg("[DISKDELETE] setOS: " .. program.detectedOS) vlc.msg.dbg("[DISKDELETE] program.pathSeparator: " .. p) end -- first dialog to config settings function config_gui() if(d) then d:delete() end d = vlc.dialog("DISKDELETE") h1 = d:add_label("<h3>Config DISKDELETE first</h3><br>", 1, 1, 1, 1) exportLogs = d:add_check_box("ENABLE LOGS?", 3, 1, 1, 1) moveSkippedFile = d:add_check_box("MOVE SKIPPED FILES?", 3, 3, 1, 1) skipFirstPart = d:add_check_box("SKIP FIRST SECONDS?", 3, 5, 1, 1) basedirLabel = d:add_label("Directory for log files", 1, 2, 2, 1) basedirInput = d:add_text_input("", 1, 3, 3, 1) movedirLabel = d:add_label("Directory for moving files", 3, 2, 2, 1) movedirInput = d:add_text_input("", 3, 3, 3, 1) local explanationHTML = [[ <h2>Explanation of config</h2> <p> <b>Enable logs</b> create log files for moving and deleting files, error messages.<br><br> <b>Move skipped files</b> marks skipped file for moving by clicking [next].<br><br> <b>Skip first seconds</b> skips the beginning / intro of the next playing file.<br> <h3>Directories</h3><br> <b>Leave input fields blank for default directories or set your own existing directories</b><br><br> <b>Directory for log files</b> e.g. "D:\\vlc_diskdelete\\logs" without ending path separator<br><br> <b>Directory for moving files</b> e.g. in which directory to move files </p> ]] explanation = d:add_html(explanationHTML, 1, 6, 6, 1) ok = d:add_button("OK - Start DISKDELETE", submitConfig, 3, 8, 1, 1) parseConfig() d:show() end function parseConfig() if(fexists(path.configFileDestination)) then -- custom settings local f = io.open(path.configFileDestination, "r") if f ~= nil then if f:read() == "false" then exportLogs:set_checked(false) end if f:read() == "false" then moveSkippedFile:set_checked(false) end if f:read() == "false" then skipFirstPart:set_checked(false) end basedir = f:read() basedirInput:set_text(basedir) path.moveDestination = f:read() movedirInput:set_text(path.moveDestination) f:close() end else -- default settings end end -- save config in a file function saveConfig() local msg = tostring(logsEnabled).."\n"..tostring(moveSkippedFilesEnabled).."\n"..tostring(skipFirstPartEnabled).."\n"..basedir.."\n"..path.moveDestination exportInFile(msg, path.configFileDestination, "w") msg = nil end function setPaths() -- where to save logs and move files, directories must exist! path = { errorLogDestination = basedir ..p..'VLC_DISKDELETE_ERRORLOG.txt', -- error log moveDestination = "D:\\X\\Downloads\\done\\", -- in which directory to move files moveLogDestination = basedir ..p..'VLC_DISKDELETE_MOVELOG.txt', -- selected files for moving deleteLogDestination = basedir ..p..'VLC_DISKDELETE_DELETELOG.txt', -- selected files for deletion shellFileDestination = basedir ..p..'VLC_DISKDELETE_MOVE.', -- batch file with commands and paths to move configFileDestination = vlc.config.homedir() ..p.. 'VLC_DISKDELETE_CONFIG.ini' -- where to save the config } vlc.msg.dbg("[DISKDELETE] basedir="..tostring(basedir)) vlc.msg.dbg("[DISKDELETE] path.moveDestination="..tostring(path.moveDestination)) vlc.msg.dbg("[DISKDELETE] path.moveLogDestination="..tostring(path.moveLogDestination)) vlc.msg.dbg("[DISKDELETE] configFileDestination="..tostring(path.configFileDestination)) end function submitConfig() logsEnabled = exportLogs:get_checked() moveSkippedFilesEnabled = moveSkippedFile:get_checked() skipFirstPartEnabled = skipFirstPart:get_checked() basedir = basedirInput:get_text() setPaths() path.moveDestination = movedirInput:get_text() vlc.msg.dbg("[DISKDELETE] path.moveDestination="..tostring(path.moveDestination)) -- add os-dependent file extension for shell file if program.detectedOS == 'windows' then path.shellFileDestination = path.shellFileDestination .. "cmd" else path.shellFileDestination = path.shellFileDestination .. "sh" end -- create log files if logging is enabled if(logsEnabled) then moveLog = io.open(path.moveLogDestination, "a") deleteLog = io.open(path.deleteLogDestination, "a") errorLog = io.open(path.errorLogDestination, "a") end -- switch to main_gui after config d:hide() d:del_widget(h1) d:del_widget(exportLogs) d:del_widget(moveSkippedFile) d:del_widget(skipFirstPart) d:del_widget(basedirLabel) d:del_widget(basedirInput) d:del_widget(movedirLabel) d:del_widget(movedirInput) d:del_widget(explanation) d:del_widget(ok) main_gui() saveConfig() end -- creates gui function main_gui() message = d:add_label("", 1, 1, 5, 1) -- previous, next, fast forward, selectFileForDeletion, selectFileForMoving d:add_button("PREVIOUS (Alt+&P)", toPreviousFile, 1, 3, 1, 1) d:add_button("FAST FORWARD (Alt+&F)", fastForward, 2, 3, 1, 1) d:add_button("NEXT (Alt+&N)", skip, 3, 3, 1, 1) d:add_button("SELECT TO DELETE (Alt+&D)", selectFileForDeletion, 4, 3, 1, 1) d:add_button("SELECT TO MOVE (Alt+&M)", selectFileForMoving, 5, 3, 1, 1) d:add_button("CONFIG", config_gui, 6, 3, 1, 1) -- TO DELETE d:add_label("<h2>To delete</h2>", 1, 6, 5, 1) d:add_label("<b style=\"color:red;\">All files in this list will be deleted!</b>", 2, 6, 2, 1) counterLabel = d:add_label("DELETED FILES: " .. counter.deleted.. " (" .. counter.sumOfFilesize .. ")", 4, 6, 2, 1) deleteListGUI = d:add_list(1, 7, 10, 10) d:add_button("SHIFT INTO MOVELIST", shiftIntoMoveList, 1, 17) d:add_button("CLEAR LIST", clearDeleteListGUI, 2, 17) d:add_button("REMOVE FROM LIST", removeFromDeleteList, 3, 17) d:add_button("DELETE FILES FROM HARDDISK", deleteFilesInForeach,4, 17) d:add_button("EXPORT DELETE-LIST", exportDeleteList, 5, 17) d:add_label("<hr />", 1, 18, 10, 1) -- TO MOVE d:add_label("<h2>To move</h2>",1, 19, 5, 1) d:add_label("<b style=\"color:red;\">Move destination: " .. path.moveDestination .. "</b>", 2, 19, 5, 1) moveListGUI = d:add_list(1, 20, 10, 10) d:add_button("SHIFT INTO DELETELIST", shiftIntoDeleteList, 1, 30) d:add_button("CLEAR LIST", clearMoveListGUI, 2, 30) d:add_button("REMOVE FROM LIST", removeFromMoveList, 3, 30) -- os-dependent buttons if program.detectedOS == "linux" then -- TODO: performance and migration for all OS? d:add_button("MOVE ALL FILES", moveFilesInForeach, 4, 30) d:add_button("EXPORT MOVE-LIST", exportMoveList, 5, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 6, 30) else d:add_button("EXPORT MOVE-LIST", exportMoveList, 4, 30) d:add_button("CREATE SHELL FILE", createShellFileForMoving, 5, 30) end -- have to update GUIList if config_gui was reopened updateGUIList(program.deleteList, deleteListGUI) updateGUIList(program.moveList, moveListGUI) -- FOOTER d:add_label("<div align=\"right\">DISKDELETE by Caglar Yanik, 2014</div>", 1, 31, 6, 1) d:show() end --[[ PLAYLIST OPERATIONS ---------------------------------------------------------]] -- skip to previous file function toPreviousFile() -- TODO: if playlist isn't empty vlc.playlist.prev() vlc.msg.dbg("[DISKDELETE] skip to previous file") end -- skip to next file function skip() -- TODO: check if item is last? if playlist isn't empty! if (moveSkippedFilesEnabled) then -- insert skipped item automatically to movelist if this option is enabled selectFileForMoving() else vlc.playlist.next() vlc.msg.dbg("[DISKDELETE] skip to next file") end collectgarbage() end -- fast forward, jumps by program.durationDivider of duration function fastForward() local input, item, durationInSeconds, durationDividerTotal, currentPosition, formattedDuration input = vlc.object.input() item = vlc.input.item() if (item:duration() > 0) then -- this should prevent stucking of vlc if duration is unknown durationInSeconds = item:duration() - item:duration() % 1 -- instead of math.floor for better perfomance durationDividerTotal = (durationInSeconds / program.durationDivider) - (durationInSeconds / program.durationDivider) % 1 currentPosition = (vlc.var.get(input, "time") - vlc.var.get(input, "time") % 1) if ((currentPosition + durationDividerTotal) < durationInSeconds) then vlc.var.set(input, "time", currentPosition + durationDividerTotal) -- fast forward else -- if timeline goes to end jumping is unnecessary skip() end else Logger("fastForward: duration is less than / equals 0") end end --[[ LIST FUNCTIONS ---------------------------------------------------------]] -- checks if element is already in table function tableContains(t, element) for k, v in pairs(t) do vlc.msg.dbg("[DISKDELETE] tableContains: k="..k.." v="..v) if v == element then return true end end return false end -- insert current item into list if it isn't already in list function selectFileForAction(list, GUIList, action) if list ~= nil then if (tableContains(list, getFilepath()) == false) then -- if item isn't already in list then insert in list table.insert(list, getFilepath()) updateGUIList(list, GUIList) -- updates the GUI list if(logsEnabled) then if(action == "moving") then moveLog:write(getFilepath().. "\n") -- TODO: \n is Windows style moveLog:flush() elseif(action == "deleting") then deleteLog:write(getFilepath().. "\n") deleteLog:flush() end end vlc.msg.info("[DISKDELETE] select for ".. action .. ": " .. getFilepath()) end vlc.playlist.next() else Logger("selectFileForAction(list, GUIList, action): list is nil!") end end -- remove selected items from list function removeFromList(list, GUIList) if list ~= nil then local selected = GUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] removeFromList selected: k=" .. k .. " v=" .. v) if tableContains(list, v) == true then list[k] = nil -- instead of: table.remove(list, k) end end updateGUIList(list,GUIList) else Logger("removeFromList(list, GUIList): list is nil!") end end -- shift selected files from one list to another, e.g. from move list to delete list function shiftIntoAnotherList(oldList, newList, oldGUIList, newGUIList) if oldList ~= nil then local selected = oldGUIList:get_selection() for k, v in pairs(selected) do vlc.msg.dbg("[DISKDELETE] shiftIntoAnotherList selected: k=" .. k .. " v=" .. v) if tableContains(oldList, v) == true then oldList[k] = nil table.insert(newList, v) end end updateGUIList(oldList, oldGUIList) updateGUIList(newList, newGUIList) else Logger("shiftIntoAnotherList(): oldList is nil!") end end -- clears the list completely function clearList(list, GUIList) for k, v in pairs(list) do -- delete all items in list list[k] = nil end GUIList:clear() collectgarbage() end -- updates GUI list function updateGUIList(list, GUIList) GUIList:clear() for k, v in pairs(list) do GUIList:add_value(v, k) end d:update() end -- exports all list items into a file function exportList(list, destination) -- TODO: check error handling if list ~= nil and destination ~= nil then if list[1] ~= nil then local concat = table.concat(list, "\n") exportInFile(concat, destination) else end else Logger("exportList(list, destination): list or destination is nil!") end end --[[ DELETE FUNCTIONS ---------------------------------------------------------]] -- shift selected items from deleteList to moveList function shiftIntoMoveList() shiftIntoAnotherList(program.deleteList, program.moveList, deleteListGUI, moveListGUI) end -- remove selected items from delete-list function removeFromDeleteList() removeFromList(program.deleteList, deleteListGUI) end -- select current file for deletion function selectFileForDeletion() selectFileForAction(program.deleteList, deleteListGUI, "deleting") end -- delete all files in array deleteList function deleteFilesInForeach() for k, v in pairs(program.deleteList) do deleteFile(k) end updateGUIList(program.deleteList, deleteListGUI) counterLabel:set_text("DELETED FILES: " .. counter.deleted.. " (" .. math.ceil(counter.sumOfFilesize / 1024 / 1024) .. " MB)") updatePlaylist() end -- deletion of one file function deleteFile(_index) if program.deleteList[_index]~=nil then local filesize = fsize(program.deleteList[_index]) local retval, err = os.remove(program.deleteList[_index]) if(retval == nil) then -- error handling; if deletion failed, print why Logger( "deleteFile() " .. err) else vlc.msg.info("[DISKDELETE] deleted: " .. program.deleteList[_index]) counter.deleted = counter.deleted + 1 counter.sumOfFilesize = counter.sumOfFilesize + filesize program.deleteList[_index]=nil end end collectgarbage() end -- exports all deleteList items into a file function exportDeleteList() exportList(program.deleteList, path.deleteLogDestination) end -- clears the list completely function clearDeleteListGUI() clearList(program.deleteList,deleteListGUI) end --[[ MOVE FUNCTIONS ---------------------------------------------------------]] function shiftIntoDeleteList() shiftIntoAnotherList(program.moveList, program.deleteList, moveListGUI, deleteListGUI) end -- remove selected items from move-list function removeFromMoveList() removeFromList(program.moveList, moveListGUI) end -- select current file for moving function selectFileForMoving() selectFileForAction(program.moveList, moveListGUI, "moving") end -- move all selected files function moveFilesInForeach() -- TODO: error handling! -- TODO: table.foreach is deprecated table.foreach(program.moveList,moveFile) updateGUIList(program.moveList, moveListGUI) end -- moving of one file function moveFile(_index) if program.moveList[_index] ~= nil then local retStatus = os.execute("MOVE \"" .. program.moveList[_index] .. "\" \"" .. path.moveDestination .. "\"") -- moving!; add " && pause" to this statement for debugging if(retStatus == 1) then -- error handling; if move failed Logger("moveFile(): nothing defined") -- TODO else skip() vlc.msg.info("[DISKDELETE] moved: " .. program.moveList[_index] .. " to " .. path.moveDestination) program.moveList[_index]=nil counter.moved = counter.moved + 1 -- TODO: not in use yet -- TODO: remove also from playlist end end collectgarbage() end -- exports all moveList items into a file function exportMoveList() exportList(program.moveList, path.moveLogDestination) end function createShellFileForMoving() if program.moveList ~= nil then local msg = "" if program.detectedOS == "windows" then -- create batch file msg = "REM " .. os.date() .. "\n" msg = msg .. "MKDIR " .. path.moveDestination .. "\n\n" for k, v in pairs(program.moveList) do msg = msg .. "MOVE \"" .. v .. "\" \"" .. path.moveDestination .. "\"\n" end msg = msg .. "\nPAUSE" elseif program.detectedOS == "linux" then -- create bash file -- TODO: test msg = msg .. "#!/bin/sh\r" msg = msg .. "MKDIR -p ".. path.moveDestination .."\r\r" for k, v in pairs(program.moveList) do msg = msg .. "MV '" .. v .. "' '" .. path.moveDestination .. "'\r" end msg = msg .. "\rpause 'Press [Enter] key to continue...'" else Logger("Neither Windows nor Linux is detected!") end -- TODO: msg can't be nil! => creates shell file although list is empty! if msg ~= nil then exportInFile(msg, path.shellFileDestination) else Logger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): msg is nil!") end else Logger("[DISKDELETE] createShellFile(program.moveList, path.moveDestination): program.moveList is nil!") end end -- clears the list completely function clearMoveListGUI() clearList(program.moveList,moveListGUI) end --[[ PLAYLIST FUNCTIONS ---------------------------------------------------------]] -- source: http://addons.videolan.org/content/show.php/Playlist+Cleaner?content=155249 -- author of original extension: Joseph M. Pence ("basaquer") -- I've modified it for my extension -- TODO: linux migration function updatePlaylist() local fileset = {} for i, v in pairs(vlc.playlist.get("playlist",false).children) do if fileset[v.path] then vlc.msg.dbg("updatePlaylist(): v.path=" .. v.path) vlc.playlist.delete(tonumber(v.id)) else fileset[v.path] = 1 end if check_orphans(v.path)==false then vlc.playlist.delete(tonumber(v.id)) end end end --TODO: linux-migration function check_orphans(filepath) local pathval if program.detectedOS == "windows" then pathval = string.sub(filepath, 9) elseif program.detectedOS == "linux" then pathval = string.sub(filepath, 8) else Logger("[DISKDELETE] check_orphans(filepath): not implemented for this OS.") end if pathval==nil then return true end pathval = unescape(pathval) local file,err,code = io.open(pathval, "r") if err and code==2 then return false end end function unescape(str) newstr = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) if newstr==nil then newstr=str end return newstr end --[[ FILE, EXPORT AND OTHER FUNCTIONS ---------------------------------------------------------]] -- TODO: loop if errorLog fails because of exportInFile. function Logger(e) e = tostring(e) message:set_text("<b style=\"color:red;\">ERROR: " .. e .. "</b>") vlc.msg.err("[DISKDELETE] error: " .. e .. "; see error log here: " .. path.errorLogDestination) exportInFile(os.date() .. " - " .. e, path.errorLogDestination) end -- check this again function exportInFile(msg, destination, mode) if msg ~= nil and destination ~= nil then msg = tostring(msg) mode = mode or "a" -- standard mode is append local f, err = io.open(destination, mode) if not f then -- error handling vlc.msg.err("exportInFile(): " .. err) else -- file opened f:write(msg .. "\n") f:close() end else vlc.msg.err("exportInFile(msg, destination, mode): msg or destination is nil!") end end -- get current playing file's path, for windows style function getFilepath() -- error handling? if item... or is playing? if playlist empty? local item, uri, filepath item = vlc.input.item() uri = item:uri() -- extract it's URI filepath = vlc.strings.decode_uri(uri) -- decode %foo stuff from the URI if program.detectedOS == "windows" then filepath = string.sub(filepath,9) -- remove 'file://' prefix which is 7 chars long filepath = string.gsub(filepath,"/","\\") -- Windows style path, e.g. c:\mp3\the best.mp3 return filepath elseif program.detectedOS == "linux" then filepath = string.sub(filepath, 8) return filepath else Logger("getFilepath(): setOS(): unknown OS") end end -- get filesize function fsize(file) local f = io.open(file, "r") local size = f:seek("end") -- get file size f:close() return size end function fexists(file) local f = io.open(file, "r") if f ~= nil then io.close(f) vlc.msg.dbg("[DISKDELETE] " .. file .. " exists!") return true else vlc.msg.dbg("[DISKDELETE] " .. file .. " doesn't exist!") return false end end -- set OS and path separator function setOS() --if(string.match(os.getenv("UserProfile"), "^C:")) then -- <<< error on linux! if(os.getenv("UserProfile") ~= nil) then program.detectedOS = "windows" program.pathSeparator = "\\" elseif(string.sub(assert(assert(io.popen("uname -s", "r"))):read("*a"),0, -2) == "Linux") then io.close() program.detectedOS = "linux" program.pathSeparator = "/" else program.detectedOS = "unknown" vlc.msg.err("[DISKDELETE] unknown OS") end end -- total memory in use function collectgarbageCount() -- better perfomance since deleting math.ceil() return "collectgarbage(\"count\"):" .. collectgarbage("count") .. " KB" end function meta_changed() vlc.msg.dbg("[DISKDELETE] meta_changed;") end function input_changed() vlc.msg.dbg("[DISKDELETE] input_changed; " .. collectgarbageCount()) if (skipFirstPartEnabled) then -- if is true, skip first seconds of video to jump over the intro fastForward() end updatePlaylist() end function close() vlc.deactivate() end function deactivate() if(logsEnabled) then moveLog:close() deleteLog:close() errorLog:close() end vlc.msg.dbg("[DISKDELETE] deactivated") end

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 01 Mar 2015 17:18
by ctrl48
This script is exactly what i need. However it makes VLC crash a LOT, usually after adding one or two videos to the delete list. This makes it pretty much unusable for me. Which version of VLC do you recommend to use with this extension?

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 02 Mar 2015 21:28
by mederi

Code: Select all

function input_changed() end

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 19 Mar 2015 20:20
by ctrl48
Got it working okay with VLC version 2.0

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 06 Apr 2015 13:48
by 147852369
@meredi: Do you suggest to empty input_changed?

For all: You can pull, fork, commit, whatever this extension from here: https://bitbucket.org/alibranic/vlc_extensions/

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 14 Apr 2015 16:23
by mederi
If it is empty, then the extension works for me and it is stable.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 24 Apr 2015 22:58
by 147852369
Okay. I have to look. I think that one of the functions returns nil although I except a numeric value.

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 28 Sep 2015 17:49
by 147852369
Who wants to test DISKDELETE++?

https://bitbucket.org/alibranic/vlc_extensions/src

I tried to improve one function which is the cause for stucking. Maybe it's better now...

Image

Re: New Diskdelete for Windows and Linux [Bugs]

Posted: 05 Jan 2017 23:06
by 147852369
Hello!
I have good news. Here's a new topic about this problem: https://forum.videolan.org/viewtopic.ph ... 68#p451830

I started to develop a VLC Media Player based on JavaFX. You can delete files directly from hard drive also on Windows - without crashing! Please test and notify me about your experience in the new thread.