-- Copyright (c) 2020, Eisa AlAwadhi -- License: BSD 2-Clause License -- Creator: Eisa AlAwadhi -- Project: SmartCopyPaste -- Version: 2.2 local utils = require 'mp.utils' local msg = require 'mp.msg' local protocols local extensions local pasted = false ----------------------------USER CUSTOMIZATION SETTINGS----------------------------------- --These settings are for users to manually change some options in the script. --Keybinds can be defined in the bottom of the script. local device = nil --nil is for automatic device detection, or manually change to: 'windows' or 'mac' or 'linux' local linux_copy = 'wl-copy' --copy command that will be used in Linux. OR write a different command local linux_paste = 'wl-paste' --paste command that will be used in Linux. OR write a different command local mac_copy = 'pbcopy' --copy command that will be used in MAC. OR write a different command local mac_paste = 'pbpaste' --paste command that will be used in MAC. OR write a different command local windows_copy = 'powershell' --'powershell' is for using windows powershell to copy. OR write the copy command, e.g: ' clip' local windows_paste = 'powershell' --'powershell' is for using windows powershell to paste. OR write the paste command local paste_anything = false --false is for specific paste based on the specified extensions and protocols. Change to true so paste accepts anything (not recommended to change this). if not paste_anything then protocols = { --add below (after a comma) any protocol you want SmartCopyPaste to work with; e.g: ,'ftp://' 'https?://' ,'magnet:' } extensions = { --add below (after a comma) any extension you want SmartCopyPaste to work with; e.g: ,'pdf' --video & audio 'ac3', 'a52', 'eac3', 'mlp', 'dts', 'dts-hd', 'dtshd', 'true-hd', 'thd', 'truehd', 'thd+ac3', 'tta', 'pcm', 'wav', 'aiff', 'aif', 'aifc', 'amr', 'awb', 'au', 'snd', 'lpcm', 'yuv', 'y4m', 'ape', 'wv', 'shn', 'm2ts', 'm2t', 'mts', 'mtv', 'ts', 'tsv', 'tsa', 'tts', 'trp', 'adts', 'adt', 'mpa', 'm1a', 'm2a', 'mp1', 'mp2', 'mp3', 'mpeg', 'mpg', 'mpe', 'mpeg2', 'm1v', 'm2v', 'mp2v', 'mpv', 'mpv2', 'mod', 'tod', 'vob', 'vro', 'evob', 'evo', 'mpeg4', 'm4v', 'mp4', 'mp4v', 'mpg4', 'm4a', 'aac', 'h264', 'avc', 'x264', '264', 'hevc', 'h265', 'x265', '265', 'flac', 'oga', 'ogg', 'opus', 'spx', 'ogv', 'ogm', 'ogx', 'mkv', 'mk3d', 'mka', 'webm', 'weba', 'avi', 'vfw', 'divx', '3iv', 'xvid', 'nut', 'flic', 'fli', 'flc', 'nsv', 'gxf', 'mxf', 'wma', 'wm', 'wmv', 'asf', 'dvr-ms', 'dvr', 'wtv', 'dv', 'hdv', 'flv','f4v', 'f4a', 'qt', 'mov', 'hdmov', 'rm', 'rmvb', 'ra', 'ram', '3ga', '3ga2', '3gpp', '3gp', '3gp2', '3g2', 'ay', 'gbs', 'gym', 'hes', 'kss', 'nsf', 'nsfe', 'sap', 'spc', 'vgm', 'vgz', 'm3u', 'm3u8', 'pls', 'cue', --images "ase", "art", "bmp", "blp", "cd5", "cit", "cpt", "cr2", "cut", "dds", "dib", "djvu", "egt", "exif", "gif", "gpl", "grf", "icns", "ico", "iff", "jng", "jpeg", "jpg", "jfif", "jp2", "jps", "lbm", "max", "miff", "mng", "msp", "nitf", "ota", "pbm", "pc1", "pc2", "pc3", "pcf", "pcx", "pdn", "pgm", "PI1", "PI2", "PI3", "pict", "pct", "pnm", "pns", "ppm", "psb", "psd", "pdd", "psp", "px", "pxm", "pxr", "qfx", "raw", "rle", "sct", "sgi", "rgb", "int", "bw", "tga", "tiff", "tif", "vtf", "xbm", "xcf", "xpm", "3dv", "amf", "ai", "awg", "cgm", "cdr", "cmx", "dxf", "e2d", "egt", "eps", "fs", "gbr", "odg", "svg", "stl", "vrml", "x3d", "sxd", "v2d", "vnd", "wmf", "emf", "art", "xar", "png", "webp", "jxr", "hdp", "wdp", "cur", "ecw", "iff", "lbm", "liff", "nrrd", "pam", "pcx", "pgf", "sgi", "rgb", "rgba", "bw", "int", "inta", "sid", "ras", "sun", "tga", --other types 'torrent' } ---------------------------END OF USER CUSTOMIZATION SETTINGS------------------------ else protocols = {''} extensions = {''} end if not device then if os.getenv('windir') ~= nil then device = 'windows' elseif os.execute '[ -d "/Applications" ]' == 0 and os.execute '[ -d "/Library" ]' == 0 or os.execute '[ -d "/Applications" ]' == true and os.execute '[ -d "/Library" ]' == true then device = 'mac' else device = 'linux' end end function handleres(res, args) if not res.error and res.status == 0 then return res.stdout else msg.error("There was an error getting "..device.." clipboard: ") msg.error(" Status: "..(res.status or "")) msg.error(" Error: "..(res.error or "")) msg.error(" stdout: "..(res.stdout or "")) msg.error("args: "..utils.to_string(args)) return '' end end function os.capture(cmd, raw) local f = assert(io.popen(cmd, 'r')) local s = assert(f:read('*a')) f:close() if raw then return s end s = string.gsub(s, '^%s+', '') s = string.gsub(s, '%s+$', '') s = string.gsub(s, '[\n\r]+', ' ') return s end local function get_extension(path) match = string.match(path, '%.([^%.]+)$' ) if match == nil then return 'nomatch' else return match end end local function get_extentionpath(path) match = string.match(path,'(.*)%.([^%.]+)$') if match == nil then return 'nomatch' else return match end end local function has_extension (tab, val) for index, value in ipairs(tab) do if value == val then return true end end return false end local function starts_protocol (tab, val) for index, value in ipairs(tab) do if (val:find(value) == 1) then return true end end return false end function get_clipboard() local clip if device == 'linux' then clip = os.capture(linux_paste, false) return clip elseif device == 'windows' then if windows_paste == 'powershell' then local args = { 'powershell', '-NoProfile', '-Command', [[& { Trap { Write-Error -ErrorRecord $_ Exit 1 } $clip = Get-Clipboard -Raw -Format Text -TextFormatType UnicodeText if ($clip) { $clip = $clip } else { $clip = Get-Clipboard -Raw -Format FileDropList } $u8clip = [System.Text.Encoding]::UTF8.GetBytes($clip) [Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length) }]] } return handleres(utils.subprocess({ args = args, cancellable = false }), args) else clip = os.capture(windows_paste, false) return clip end elseif device == 'mac' then clip = os.capture(mac_paste, false) return clip end return '' end function set_clipboard(text) local pipe if device == 'linux' then pipe = io.popen(linux_copy, 'w') pipe:write(text) pipe:close() elseif device == 'windows' then if windows_copy == 'powershell' then local res = utils.subprocess({ args = { 'powershell', '-NoProfile', '-Command', string.format([[& { Trap { Write-Error -ErrorRecord $_ Exit 1 } Add-Type -AssemblyName PresentationCore [System.Windows.Clipboard]::SetText('%s') }]], text) } }) else pipe = io.popen(windows_copy,'w') pipe:write(text) pipe:close() end elseif device == 'mac' then pipe = io.popen(mac_copy,'w') pipe:write(text) pipe:close() end return '' end local function copy() local filePath = mp.get_property_native('path') if (filePath ~= nil) then local time = math.floor(mp.get_property_number('time-pos')) set_clipboard(filePath..' |time='..tostring(time)) mp.osd_message("Copied:\n"..filePath..' |time='..tostring(time)) else mp.osd_message('Failed to Copy\nNo Video Found') end end local function copy_path() local filePath = mp.get_property_native('path') if (filePath ~= nil) then set_clipboard(filePath) mp.osd_message("Copied Video Only:\n"..filePath) else return false end end function paste() local clip = get_clipboard() clip = string.gsub(clip, "[\r\n]" , "") local filePath = mp.get_property_native('path') local time if string.match(clip, '(.*) |time=') then videoFile = string.match(clip, '(.*) |time=') time = string.match(clip, ' |time=(.*)') elseif string.match(clip, '^\"(.*)\"$') then videoFile = string.match(clip, '^\"(.*)\"$') else videoFile = clip end local currentVideoExtension = string.lower(get_extension(videoFile)) local currentVideoExtensionPath = (get_extentionpath(videoFile)) if (filePath == nil) and has_extension(extensions, currentVideoExtension) and (currentVideoExtensionPath~= '') then mp.commandv('loadfile', videoFile) mp.osd_message("Pasted:\n"..videoFile) elseif (filePath == nil) and (starts_protocol(protocols, videoFile)) then mp.commandv('loadfile', videoFile) mp.osd_message("Pasted:\n"..videoFile) elseif (filePath ~= nil) and (filePath ~= videoFile) and has_extension(extensions, currentVideoExtension) and (currentVideoExtensionPath~= '') or (starts_protocol(protocols, videoFile)) and (filePath ~= videoFile) then mp.commandv('loadfile', videoFile, 'append-play') mp.osd_message('Pasted Into Playlist:\n'..videoFile) elseif (filePath == videoFile) and (time == nil) then mp.osd_message('Same file is already running:\n'..clip) elseif (filePath == videoFile) and (time ~= nil) then mp.commandv('seek', time, 'absolute', 'exact') mp.osd_message('Resumed to Copied Time') else mp.osd_message('Failed to Paste\nPasted Unsupported Item:\n'..clip) end pasted = true end function paste_playlist() local clip = get_clipboard() clip = string.gsub(clip, "[\r\n]" , "") local filePath = mp.get_property_native('path') if string.match(clip, '(.*) |time=') then videoFile = string.match(clip, '(.*) |time=') elseif string.match(clip, '^\"(.*)\"$') then videoFile = string.match(clip, '^\"(.*)\"$') else videoFile = clip end local currentVideoExtension = string.lower(get_extension(videoFile)) local currentVideoExtensionPath = (get_extentionpath(videoFile)) if has_extension(extensions, currentVideoExtension) and (currentVideoExtensionPath~= '') or (starts_protocol(protocols, videoFile)) then mp.commandv('loadfile', videoFile, 'append-play') mp.osd_message('Pasted Into Playlist:\n'..videoFile) else mp.osd_message('Failed to Add Into Playlist\nPasted Unsupported Item:\n'..clip) end pasted = true end mp.register_event('end-file', function() pasted = false end) mp.register_event('file-loaded', function() if (pasted == true) then local clip = get_clipboard() local time = string.match(clip, ' |time=(.*)') local videoFile = string.match(clip, '(.*) |time=') local filePath = mp.get_property_native('path') if (filePath == videoFile) and (time ~= nil) then mp.commandv('seek', time, 'absolute', 'exact') end else return false end end) ---------------------------KEYBINDS CUSTOMIZATION SETTINGS--------------------------------- if device == 'mac' then --MAC OS Keybinds mp.add_key_binding('Meta+c', 'copy', copy) mp.add_key_binding('Meta+C', 'copyCaps', copy) mp.add_key_binding('Meta+v', 'paste', paste) mp.add_key_binding('Meta+V', 'pasteCaps', paste) mp.add_key_binding('Meta+alt+c', 'copy-path', copy_path) mp.add_key_binding('Meta+alt+C', 'copy-pathCaps', copy_path) mp.add_key_binding('Meta+alt+v', 'paste-playlist', paste_playlist) mp.add_key_binding('Meta+alt+V', 'paste-playlistCaps', paste_playlist) else --Windows and Linux Keybinds mp.add_key_binding('ctrl+c', 'copy', copy) mp.add_key_binding('ctrl+C', 'copyCaps', copy) mp.add_key_binding('ctrl+v', 'paste', paste) mp.add_key_binding('ctrl+V', 'pasteCaps', paste) mp.add_key_binding('ctrl+alt+c', 'copy-path', copy_path) mp.add_key_binding('ctrl+alt+C', 'copy-pathCaps', copy_path) mp.add_key_binding('ctrl+alt+v', 'paste-playlist', paste_playlist) mp.add_key_binding('ctrl+alt+V', 'paste-playlistCaps', paste_playlist) end ---------------------END OF KEYBINDS CUSTOMIZATION SETTINGS---------------------------------