File "VLC Playlist Manager.bas"
Path: /VLC Playlist Manager/VLC Playlist Manager.bas
File size: 35.94 KB
MIME-type: text/plain
Charset: utf-8
#COMPILE EXE
#DIM ALL
'------------------------------------------------------------------------------
$VER = "1.3"
$SRC = "http://mougino.free.fr/code/VLC Playlist Manager/VLC Playlist Manager.bas"
'------------------------------------------------------------------------------
#INCLUDE ONCE "win32api.inc"
#INCLUDE ONCE "shfolder.inc"
#INCLUDE ONCE "commctrl.inc"
#INCLUDE ONCE "inc/registry.inc"
#INCLUDE ONCE "inc/savepos.inc"
#INCLUDE ONCE "inc/rdir.inc"
#INCLUDE ONCE "inc/exe2unix.inc"
#INCLUDE ONCE "inc/mymsgbox.inc"
#INCLUDE ONCE "inc/selfupdate.inc"
'------------------------------------------------------------------------------
#RESOURCE ".\res\vpm.pbr"
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
%WM_LOADPL = %WM_USER + 1000
%WM_STARTPL = %WM_USER + 1001
%WM_RESUMEPL = %WM_USER + 1002
%WM_UPDATEMF = %WM_USER + 1003
'------------------------------------------------------------------------------
$VIDEXT = ",.3gp,.amv,.asf,.avi,.divx,.flv,.m2ts,.m2v,.m4v,.mkv,.mov,.mp4,.mpeg,.mpg,.ogg,.ogv,.qt,.rm,.rmvb,.swf,.vob,.webm,.wmv,"
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
' Changelog
'------------------------------------------------------------------------------
' v1.3
' [X] Fix for Wine 11.0 breaking 'start.exe' retrocompatibility
' v1.2
' [X] Add a program updater!
' [X] Fix 'recent' combobox name when switching to another playlist
' [X] Improve readability of episode names in listview
' v1.1
' [X] Now supports running in Linux via wine!
' [X] Propose to install and make a Linux App shortcut at startup
' [X] Hidden feature: double-click the eye to manually kill VLC Listener
' [X] Fix long paths in media listview
' [X] Fix new playlist name not appearing in 'recent' combobox
' [X] Force vlc to start playlists with "--no-random" option
' v1.0
' [X] Now supports drag & drop of folders to create a resumable playlist!
' [X] Update documentation with drag & drop of folders
' [X] Fix VLC Listener to detect VLC instances in languages other than english
' [X] Handle vlc 64-bit installation folder
' v0.3
' [X] Fix badly handled UTF-8 characters
' [X] Fix long paths in recent playlist combobox
' v0.2
' [X] Add eye icon to show activity of VLC Listener
' [X] Add (!) icon to alert last VLC media couldn't be found
' [X] CenterMsgBox()
' [X] Fix relative paths broken when opened from local playlist
' [X] Fix xspf support
' [X] Fix recent playlist combobox duplicates
' [X] Fix empty recent playlists combobox when opening an invalid playlist
' v0.1
' [X] Double-click on a media file resumes the playlist at this point
' [X] Button "Start playlist" selects first media then start playlist
' [X] Button "Resume playlist" selects last media and resumes playlist
' [X] Make dialog able to receive files by drag & drop
' [X] Start/resume drag and dropped playlist
' [X] Save last played file from playlist
' [X] Buttons:
' [X] Start/Resume playlist
' [X] Help
' [X] Create a temp playlist starting at current media till last media of playlist
' [X] Make VLC run this temp playlist
' [X] VLC listener (every 2s)
' [X] check last played media in the .ini, update g_LastMf + listview accordingly
' [X] check if VLC has been killed -> if yes stop VLC listener
'------------------------------------------------------------------------------
GLOBAL g_VlcPath AS STRING ' vlc path
GLOBAL g_VlcCfg AS STRING ' vlc config file path
GLOBAL g_LastPl AS STRING ' the last playlist opened
GLOBAL g_TmpPl AS STRING ' the local temp playlist created by VPM
GLOBAL g_LastMf AS STRING ' the last media file played from the current playlist
GLOBAL g_Mf() AS STRING ' the list of media files for the current playlist
GLOBAL g_TmpDir AS STRING ' temp dir where to store program files
GLOBAL g_OnUnix AS LONG ' if we are on unix or not
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB LogMe(BYVAL lg AS STRING)
' Only produce logs during dev:
IF NOT EXISTS(LEFT$(EXE.FULL$,-3) + "log") THEN EXIT SUB
LOCAL ff AS LONG
LOCAL d, t AS STRING
' Create TimeStamp
d = DATE$
d = RIGHT$(d,4) + LEFT$(d,2) + MID$(d, 4, 2)
t = TIME$
REPLACE ":" WITH "" IN t
t = d + "-" + t + ","
t = t + FORMAT$((TIMER*1000) MOD 1000, "000")
' Write to log file
ff = FREEFILE
OPEN LEFT$(EXE.FULL$,-3) + "log" FOR APPEND AS #ff
PRINT #ff, "[" + t + "] " + lg
CLOSE #ff
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB AutoDetectVlc()
LOCAL e AS STRING
' Specific if we run from Unix/Wine
IF g_OnUnix THEN
LET g_VlcPath = GetUnixRet("whereis vlc")
IF LEN(g_VlcPath) THEN
' Parse the vlc path from the string "vlc: /usr/bin/vlc /usr/lib/x86_64-linux-gnu/vlc ..."
g_VlcPath = TRIM$(MID$(g_VlcPath, INSTR(g_VlcPath,":") + 1))
IF INSTR(g_VlcPath, " ") THEN g_VlcPath = LEFT$(g_VlcPath, INSTR(g_VlcPath," ") - 1)
END IF
IF g_VlcPath = "" AND UnixExists("/usr/bin/vlc") THEN g_VlcPath = "/usr/bin/vlc"
EXIT SUB
END IF
' Run from Windows: get VLC path from registry
LET g_VlcPath = GETREGVALUE(%HKEY_LOCAL_MACHINE, "SOFTWARE\VideoLAN\VLC", "")
IF g_VlcPath <> "" THEN EXIT SUB
' Not found in default key > try another key
LET g_VlcPath = GETREGVALUE(%HKEY_LOCAL_MACHINE, "SOFTWARE\VideoLAN\VLC", "InstallDir")
IF g_VlcPath <> "" THEN g_VlcPath += "\vlc.exe" : EXIT SUB
' Not found via registry > try a manual method
g_VlcPath = "C:\Program Files (x86)\VideoLAN\VLC\"
e = DIR$(g_VlcPath + "vlc.exe") : DIR$ CLOSE
IF e <> "" THEN g_VlcPath += e : EXIT SUB
' Last attempt...
g_VlcPath = "C:\Program Files\VideoLAN\VLC\"
e = DIR$(g_VlcPath + "vlc.exe") : DIR$ CLOSE
IF e <> "" THEN g_VlcPath += e : EXIT SUB
' Definitely not found :(
g_VlcPath = ""
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION GetVlcLastPlayedMedia() AS STRING
LOCAL zstr AS ASCIIZ * %MAX_PATH
LOCAL r AS STRING
LOCAL i AS LONG
GetPrivateProfileString "RecentsMRL", "list", "", zstr, %MAX_PATH, (g_VlcCfg)
i = INSTR(zstr, ", ")
IF i > 0 THEN zstr = LEFT$(zstr, i-1)
r = TRIM$(zstr)
r = LTRIM$(r, "file://")
r = LTRIM$(r, "/")
r = LTRIM$(r, "home/" + ENVIRON$("USERNAME") + "/")
' LogMe "GetVlcLastPlayedMedia() returned: " + r
FUNCTION = r
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION PBMAIN () AS LONG
LOCAL e AS STRING
LOCAL ff AS LONG
' Create exe icon in Unix dock and Unix file explorer
Me2Unix 1, 1, "vpm" ' askConfirmation=%TRUE, showInAppMenu=%TRUE, dkpName="wine-vpm.desktop"
' Are we on Unix/Wine?
g_OnUnix = IsOnUnix()
LogMe STRING$(80, "-")
LogMe "Starting " + EXE.NAME$ + " from " + EXE.PATH$
LogMe "IsOnUnix() returned " + IIF$(g_OnUnix, "TRUE", "False")
' Set temp and vlc config paths
IF g_OnUnix THEN
g_TmpDir = "C:\Windows\Temp\"
g_VlcCfg = UNIX_HOME + ".config\vlc\vlc-qt-interface.conf"
ELSE
g_TmpDir = LocalAppData
g_VlcCfg = RoamingAppData + "vlc\vlc-qt-interface.ini"
END IF
LogMe "Reading VLC prefs from: " + g_VlcCfg
LogMe "Storing temp playlists in: " + g_TmpDir
' Detect VLC path
AutoDetectVlc()
IF g_VlcPath = "" THEN
MYMSGBOX 0, "VLC not detected on your system",EXE.NAME$,%MB_ICONERROR
EXIT FUNCTION
END IF
LogMe "VLC player detected at: " + g_VlcPath
' Get last playlist, if any
e = g_TmpDir + EXE.NAME$ + ".last.pl"
IF EXISTS(e) THEN
ff = FREEFILE
OPEN e FOR INPUT AS #ff
LINE INPUT #ff, g_LastPl
CLOSE #ff
END IF
LogMe "Last playlist: " + g_LastPl
' Show main dialog
ShowDialog 0
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION IsVlcAlive() AS LONG
' Search for a VLC instance currently running
LOCAL hWnd AS DWORD
LOCAL length AS LONG
LOCAL e AS STRING
IF g_OnUnix THEN
FUNCTION = 1
' LogMe "- [vlc listener] IsVlcAlive() returned: True"
EXIT FUNCTION
END IF
FUNCTION = 0
hWnd = FindWindow("Qt5QWindowIcon", "") ' VLC dialog class
IF hWnd = 0 THEN EXIT FUNCTION
length = SendMessage(hWnd, %WM_GETTEXTLENGTH, 0, 0) + 1 ' Get VLC caption length
e = SPACE$(length)
length = SendMessage(hWnd, %WM_GETTEXT, length, STRPTR(e)) ' Get VLC caption
LogMe "- [vlc listener] IsVlcAlive() returned: " + IIF$(INSTR(e,"VLC")=0,"FALSE","True")
FUNCTION = (INSTR(e, "VLC") <> 0)
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
THREAD FUNCTION VlcListener(BYVAL hDlg AS DWORD) AS DWORD
LOCAL curr_vid AS STRING
LOCAL last_vid AS STRING
LOCAL found AS LONG
curr_vid = g_LastMf
DO
SLEEP 2000
IF ISFALSE IsVlcAlive() THEN EXIT LOOP
last_vid = GetVlcLastPlayedMedia()
IF last_vid = "" THEN
CONTROL SHOW STATE hDlg, 4002, %SW_RESTORE ' VLC last media file not accessible
ELSE
CONTROL SHOW STATE hDlg, 4002, %SW_HIDE
IF last_vid <> curr_vid THEN ' VLC changed the media played
LogMe "- [vlc listener] detected media change by vlc: from " + curr_vid + " to " + last_vid
' LISTVIEW FIND EXACT hDlg, 2001, 1, FShort(last_vid) TO found
ARRAY SCAN g_Mf(), =last_vid, TO found
IF found THEN
g_LastMf = last_vid
DIALOG POST hDlg, %WM_UPDATEMF, 0, 0
curr_vid = last_vid
END IF
END IF
END IF
LOOP
FUNCTION = 1 ' done
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION DqProtect(s AS STRING) AS STRING
IF INSTR(s, " ") > 0 THEN FUNCTION = $DQ + s + $DQ ELSE FUNCTION = s
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB UpdateLV(BYVAL hDlg AS DWORD)
LOCAL i, found AS LONG
' LISTVIEW FIND EXACT hDlg, 2001, 1, FShort(g_LastMf) TO found
ARRAY SCAN g_Mf(), =g_LastMf, TO found
IF found = 0 THEN EXIT SUB
FOR i = LBOUND(g_Mf) TO UBOUND(g_Mf)
IF i < found THEN
LISTVIEW SET IMAGE hDlg, 2001, i, 2 ' played
ELSEIF i = found THEN
LISTVIEW SET IMAGE hDlg, 2001, i, 1 ' play
LISTVIEW SELECT hDlg, 2001, i
LISTVIEW VISIBLE hDlg, 2001, i
ELSE
LISTVIEW SET IMAGE hDlg, 2001, i, 0 ' no icon (media yet to be played)
END IF
NEXT
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION CreatePersistentLocalM3uFromFolder(BYVAL folder AS STRING) AS STRING
LOCAL ff, i AS LONG
LOCAL pl, e AS STRING
RDIR_DeclareLocals
LogMe "Entering CreatePersistentLocalM3uFromFolder()"
RDIR_ListFilesIn(folder, "*.*")
' Dump all files path + name to g_Mf()
REDIM g_Mf(LBOUND(RDIR_FileData) TO UBOUND(RDIR_FileData)) AS STRING
FOR i = LBOUND(RDIR_FileData) TO UBOUND(RDIR_FileData)
g_Mf(i) = RDIR_File(i)
NEXT
LogMe "- " + FORMAT$(i) + " file paths dumped to g_Mf()"
' Restrict g_Mf() to video files only
FOR i = UBOUND(g_Mf) TO LBOUND(g_Mf) STEP -1
IF INSTR($VIDEXT, ","+GetExt(g_Mf(i))+",") = 0 THEN ArrDel g_Mf(), i
NEXT i
LogMe "- g_Mf() now purged from non-video files: new size is " + FORMAT$(UBOUND(g_Mf))
' Sort g_Mf() alphabetically
ARRAY SORT g_Mf()
' Create local m3u playlist
IF g_OnUnix THEN
pl = UNIX_HOME + PATHNAME$(NAMEX, RTRIM$(folder,"\")) + ".m3u"
ELSE
pl = g_TmpDir + PATHNAME$(NAMEX, RTRIM$(folder,"\")) + ".m3u"
END IF
LogMe "- creating persistent m3u playlist: " + pl
ff = FREEFILE
OPEN pl FOR OUTPUT AS #ff
PRINT #ff, "#EXTM3U"
FOR i = LBOUND(g_Mf) TO UBOUND(g_Mf)
PRINT #ff, "#EXTINF:," + FName(g_Mf(i))
e = FFull(g_Mf(i))
IF i = LBOUND(g_Mf) OR i = UBOUND(g_Mf) THEN LogMe " o " + FName(g_Mf(i)) + " @" + e
IF i = LBOUND(g_Mf) THEN LogMe " o [...]"
PRINT #ff, e
NEXT
CLOSE #ff
LogMe "- persistent m3u playlist successfully created"
LogMe "CreatePersistentLocalM3uFromFolder() finished correctly"
FUNCTION = pl
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB CreateLocalM3uStartingFromSel(BYVAL hDlg AS DWORD)
LOCAL i, k, ff AS LONG
LOCAL e AS STRING
' LOCAL p AS STRING
LogMe "Entering CreateLocalM3uStartingFromSel()"
' Get selected media
LISTVIEW GET SELECT hDlg, 2001 TO k
LISTVIEW GET USER hDlg, 2001, k TO k
' ' Create absolute path if needed
' p = FPath(g_LastPl)
' Create local m3u playlist
ff = FREEFILE
IF g_OnUnix THEN
g_TmpPl = UNIX_HOME + "vpm.m3u"
ELSE
g_TmpPl = g_TmpDir + FName(g_LastPl) + ".m3u"
END IF
LogMe "- creating temp m3u playlist: " + g_TmpPl
OPEN g_TmpPl FOR OUTPUT AS #ff
PRINT #ff, "#EXTM3U"
FOR i = LBOUND(g_Mf) TO UBOUND(g_Mf)
IF i >= k THEN
PRINT #ff, "#EXTINF:," + FName(g_Mf(i))
e = g_Mf(i) ' Already encoded via FFull()
IF i = LBOUND(g_Mf) OR i = UBOUND(g_Mf) THEN LogMe " o " + FName(g_Mf(i)) + " @" + e
IF i = LBOUND(g_Mf) THEN LogMe " o [...]"
PRINT #ff, e
END IF
NEXT
CLOSE #ff
IF g_OnUnix THEN
KILL g_TmpDir + FName(g_LastPl) + ".m3u" ' backup just to know the last media played
FILECOPY g_TmpPl, g_TmpDir + FName(g_LastPl) + ".m3u"
g_TmpPl = "/home/" + ENVIRON$("USERNAME") + "/vpm.m3u"
END IF
LogMe "- temp m3u playlist successfully created"
LogMe "CreateLocalM3uStartingFromSel() finished correctly"
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
MACRO LaunchLocalM3u
MACROTEMP lRes
DIM lRes AS LONG
LogMe "Entering LaunchLocalM3u(M)"
LogMe "- executing: " + g_VlcPath + " --no-random " + DqProtect(g_TmpPl)
IF g_OnUnix THEN
UnixShell g_VlcPath + " --no-random " + DqProtect(g_TmpPl)
ELSE
lRes = SHELL(g_VlcPath + " --no-random " + DqProtect(g_TmpPl))
END IF
IF hThread = 0 THEN
THREAD CREATE VlcListener(CB.HNDL) TO hThread
LogMe "- vlc listener started: thread id #" + FORMAT$(hThread)
idTimer = SetTimer(CB.HNDL, 999, 2000, BYVAL 0)
CONTROL SHOW STATE CB.HNDL, 4001, %SW_RESTORE ' VLC Listener thread active
END IF
LogMe "LaunchLocalM3u(M) finished"
END MACRO
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
MACRO KillVlcListener
LogMe "Killing vlc listener..."
FOR i = 1 TO 3
CONTROL SHOW STATE CB.HNDL, 4001, %SW_HIDE
CONTROL REDRAW CB.HNDL, 4001 : DIALOG DOEVENTS
SLEEP 600
CONTROL SHOW STATE CB.HNDL, 4001, %SW_RESTORE
CONTROL REDRAW CB.HNDL, 4001 : DIALOG DOEVENTS
SLEEP 600
NEXT
THREAD CLOSE hThread TO i
hThread = 0
KillTimer CB.HNDL, idTimer
idTimer = 0
CONTROL SHOW STATE CB.HNDL, 4001, %SW_HIDE
END MACRO
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
CALLBACK FUNCTION ProcDialog
STATIC hThread AS DWORD
STATIC idTimer AS LONG
LOCAL xt AS STRING
LOCAL e AS STRING
LOCAL i AS LONG
CB_SAVEPOS ' Save & restore dialog position
M_SELF_UPDATE ' Handle program self update
SELECT CASE AS LONG CB.MSG
' Initialization handler
' ---------------------------------------------
CASE %WM_INITDIALOG
LoadRecentList CB.HNDL
DIALOG POST CB.HNDL, %WM_LOADPL, 0, 0
' User message: load last playlist, if any
' ---------------------------------------------
CASE %WM_LOADPL
e = TRIM$(COMMAND$)
IF e <> "" AND EXISTS(e) THEN ' ...passed as argument
LogMe "Loading playlist passed as argument: " + e
LoadPlaylist CB.HNDL, e
ELSEIF g_LastPl <> "" THEN
LogMe "Loading playlist from last session: " + g_LastPl
LoadPlaylist CB.HNDL, g_LastPl ' ...or from last session
END IF
' User message: start playlist from the top
' ---------------------------------------------
CASE %WM_STARTPL
CreateLocalM3uStartingFromSel CB.HNDL
CONTROL SET TEXT CB.HNDL, 3001, "Resume playlist"
LaunchLocalM3u
' User message: resume playlist
' ---------------------------------------------
CASE %WM_RESUMEPL
CreateLocalM3uStartingFromSel CB.HNDL
LaunchLocalM3u
' User message: last played media file changed
' ---------------------------------------------
CASE %WM_UPDATEMF
UpdateLV CB.HNDL
CreateLocalM3uStartingFromSel CB.HNDL
' Drag and drop playlist on program to open it
' ---------------------------------------------
CASE %WM_DROPFILES
IF DragQueryFile(CB.WPARAM, -1, BYVAL 0, 0) > 1 THEN EXIT FUNCTION ' ignore multiple
LOCAL zStr AS ASCIIZ * %MAX_PATH
DragQueryFile CB.WPARAM, i, zStr, SIZEOF(zStr)
e = TRIM$(zStr)
DragFinish CB.WPARAM
LogMe "User dragged and dropped: " + e
xt = GetExt(e)
SELECT CASE xt
' Valid playlist > load it!
CASE ".m3u", ".m3u8", ".xspf"
LoadPlaylist CB.HNDL, e
CASE ELSE
' Else: test if it's a folder
IF (GETATTR(e) AND %SUBDIR) = %SUBDIR THEN
e = CreatePersistentLocalM3uFromFolder(e)
LoadPlaylist CB.HNDL, e
END IF
END SELECT
' Timer (2s) to check on VLC Listener thread
' ---------------------------------------------
CASE %WM_TIMER
IF hThread <> 0 THEN
THREAD STATUS hThread TO i
IF i <> &H103 THEN
KillVlcListener
END IF
END IF
' Double-click on listview item to lauch media file
' --------------------------------------------------
CASE %WM_NOTIFY
LOCAL pLV AS LVUNION PTR
pLV = CB.LPARAM
IF 2001 = @pLV.NMHDR.IDFROM _
AND %NM_DBLCLK = @pLV.NMHDR.CODE THEN
' Force-stop VLC Listener to avoid resuming an old "last played media"
KillVlcListener
' Set double-clicked media as last media file
LISTVIEW GET SELECT CB.HNDL, 2001 TO i
LISTVIEW GET USER CB.HNDL, 2001, i TO i
g_LastMf = g_Mf(i)
' Update the listview, create and start local playlist
UpdateLV CB.HNDL
CreateLocalM3uStartingFromSel CB.HNDL
LaunchLocalM3u
END IF
CASE %WM_COMMAND ' Process control notifications
SELECT CASE AS LONG CB.CTL
' Double-click on "Playlists" label: secret feature!
' -----------------------------------------------------------------
CASE 1001
IF CB.CTLMSG = %STN_DBLCLK THEN
i = SHELL("notepad " + g_TmpDir + EXE.NAME$ + ".lst")
END IF
' New selection in "Recent playlists" combobox: change playlist
' -----------------------------------------------------------------
CASE 1002
IF CB.CTLMSG = %CBN_SELENDOK THEN
COMBOBOX GET SELECT CB.HNDL, CB.CTL TO i
COMBOBOX GET TEXT CB.HNDL, CB.CTL, i TO e
LogMe "New recent playlist picked by user! " + $DQ + e +$DQ
IF LEFT$(e, 1) = "<" THEN EXIT FUNCTION ' <none loaded>
LoadPlaylist CB.HNDL, e
END IF
' Button "Load/Change playlist"
' -----------------------------------------------------------------
CASE 1003
IF CB.CTLMSG = %BN_CLICKED OR CB.CTLMSG = 1 THEN
e = CHR$("VLC playlist (*.m3u *.m3u8 *.xspf)", 0)
e += CHR$("*.m3u;*.m3u8;*.xspf", 0)
DISPLAY OPENFILE CB.HNDL, -120, 0, "Load playlist", "", e, _
"", "", %OFN_FILEMUSTEXIST TO e
IF e = "" THEN EXIT FUNCTION
LoadPlaylist CB.HNDL, e
END IF
' Button "Start/Resume playlist"
' -----------------------------------------------------------------
CASE 3001
CreateLocalM3uStartingFromSel CB.HNDL
CONTROL SET TEXT CB.HNDL, 3001, "Resume playlist"
LaunchLocalM3u
' Button "Help"
' -----------------------------------------------------------------
CASE 3002
ShellExecute %NULL, "open", "http://mougino.free.fr/vpm/", "", "", %SW_SHOW
' VLC Listener ("eye" icon)
' -----------------------------------------------------------------
CASE 4001
IF CB.CTLMSG = %STN_DBLCLK THEN
KillVlcListener
END IF
END SELECT
END SELECT
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB ParsePlaylist(BYVAL file AS STRING, BYREF arr() AS STRING)
' Parse a playlist and return an array of its media files
LOCAL ff AS LONG
LOCAL n AS LONG
LOCAL e AS STRING
IF NOT EXISTS(file) THEN EXIT SUB
ff = FREEFILE
OPEN file FOR INPUT ACCESS READ LOCK SHARED AS #ff
IF RIGHT$(LCASE$(file),5) = ".xspf" THEN
DO
LINE INPUT #ff, e : e = TRIM$(e, ANY $SPC+$TAB)
IF INSTR(e, "<location>") <> 1 THEN ITERATE DO
e = LTRIM$(e, "<location>")
e = RTRIM$(e, "</location>")
IF n = 0 THEN DIM arr(0) ELSE REDIM PRESERVE arr(n)
arr(n) = e
INCR n
LOOP UNTIL EOF(#ff)
ELSEIF RIGHT$(LCASE$(file),4) = ".m3u" OR RIGHT$(LCASE$(file),5) = ".m3u8" THEN
DO
LINE INPUT #ff, e
IF LEFT$(e,1) = "#" THEN ITERATE DO
IF n = 0 THEN DIM arr(0) ELSE REDIM PRESERVE arr(n)
arr(n) = e
INCR n
LOOP UNTIL EOF(#ff)
END IF
CLOSE #ff
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB ArrDel(BYREF arr() AS STRING, BYVAL idx AS LONG)
' Remove an array entry at index #idx and redim/preserve the rest of the array
IF idx < LBOUND(arr) OR idx > UBOUND(arr) THEN EXIT SUB
LOCAL j AS LONG
FOR j = idx TO UBOUND(arr)-1
arr(j) = arr(j+1)
NEXT
REDIM PRESERVE arr(LBOUND(arr) TO UBOUND(arr)-1)
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION GetExt(filePath AS STRING) AS STRING
' Return lower case extension for a file, if any, including the dot
LOCAL i AS LONG
i = INSTR(-1, filePath, ".")
IF i = 0 THEN EXIT FUNCTION
FUNCTION = LCASE$(MID$(filePath, i))
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION FFull(filePath AS STRING) AS STRING
' Return the url-encoded full file path in order to populate an .m3u playlist
LOCAL r AS STRING
r = filePath
IF g_OnUnix THEN
r = ".wine/dosdevices/" + LCASE$(LEFT$(r,1)) + MID$(r,2)
ELSE
r = "file:///" + r
END IF
REPLACE "%" WITH "%25" IN r
REPLACE ":" WITH "%3A" IN r
REPLACE " " WITH "%20" IN r
REPLACE "\" WITH "/" IN r
FUNCTION = r
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION FShort(filePath AS STRING) AS STRING
' Opposite of FFull: url-decode and shorten file path to display in listview
LOCAL r AS STRING
LOCAL i AS LONG
r = filePath
IF INSTR(r, ".wine/dosdevices/") = 1 THEN
r = MID$(r, LEN(".wine/dosdevices/") + 1)
r = UCASE$(LEFT$(r,1)) + MID$(r,2)
ELSEIF INSTR(r, "file:///") = 1 THEN
r = MID$(r, LEN("file:///") + 1)
END IF
REPLACE "/" WITH "\" IN r
REPLACE "%20" WITH " " IN r
REPLACE "%3A" WITH ":" IN r
REPLACE "%25" WITH "%" IN r
IF LEN(r) > 50 THEN
i = INSTR(-1, r, "\")
IF i = 0 THEN i = LEN(r) - 28
r = LEFT$(r,18) + "..." + MID$(r,i)
END IF
FUNCTION = r
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION FPath(filePath AS STRING) AS STRING
' Return url-encoded path for a file, including last slash
LOCAL r AS STRING
LOCAL i AS LONG
r = FShort(filePath)
i = INSTR(-1, r, "\")
IF i > 0 THEN r = LEFT$(r, i)
FUNCTION = FFull(r)
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION FName(filePath AS STRING) AS STRING
' Return file name without extension from a full file uri
LOCAL r AS STRING
LOCAL i AS LONG
r = filePath
REPLACE "/" WITH "\" IN r
i = INSTR(-1, r, "\")
IF i > 0 THEN r = MID$(r, i+1)
i = INSTR(-1, r, ".")
IF i > 0 THEN r = LEFT$(r, i-1)
FUNCTION = LTRIM$(FShort(r), ".")
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION PathEnv(BYVAL filePath AS STRING) AS STRING
' Return full file path with ENV variables "%TMP%" or "%LocalAppData%" if any
IF g_OnUnix THEN
REPLACE g_TmpDir WITH "%TMP%\" IN filePath
REPLACE UNIX_HOME WITH "~\" IN filePath
ELSE
REPLACE g_TmpDir WITH "%LocalAppData%\" IN filePath
END IF
FUNCTION = filePath
END FUNCTION
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB LoadPlaylist(BYVAL hDlg AS DWORD, BYVAL playlistPath AS STRING)
LOCAL e AS STRING
LOCAL i, ff AS LONG
LOCAL found AS LONG
LogMe "Entering LoadPlaylist()"
' Reset last played media file
g_LastMf = ""
REDIM g_Mf(-1)
' Translate playlistPath
REPLACE "%LocalAppData%\" WITH g_TmpDir IN playlistPath
REPLACE "%TMP%\" WITH g_TmpDir IN playlistPath
REPLACE "~\" WITH UNIX_HOME IN playlistPath
' Load playlist content into listview
LISTVIEW RESET hDlg, 2001
IF NOT EXISTS(playlistPath) THEN
LogMe "- " + playlistPath + " does not exist > abandoning"
CONTROL DISABLE hDlg, 3001 ' Start/Resume playlist
EXIT SUB
END IF
ParsePlaylist playlistPath, g_Mf()
IF UBOUND(g_Mf) < 0 THEN
CONTROL SET TEXT hDlg, 3001, "Start playlist"
CONTROL DISABLE hDlg, 3001 ' Start/Resume playlist
LogMe "- Playlist " + playlistPath + " is invalid!"
MYMSGBOX hDlg, "Invalid playlist", EXE.NAME$, %MB_ICONWARNING
EXIT SUB
END IF
CONTROL ENABLE hDlg, 3001 ' Start/Resume playlist
FOR i = UBOUND(g_Mf) TO LBOUND(g_Mf) STEP -1
IF i = UBOUND(g_Mf) OR i = LBOUND(g_Mf) THEN LogMe "- inserting: " + g_Mf(i)
IF i = UBOUND(g_Mf) THEN LogMe "- inserting: [...]"
LISTVIEW INSERT ITEM hDlg, 2001, 1, 0, FShort(g_Mf(i))
LISTVIEW SET USER hDlg, 2001, 1, i ' pointer to media file path: g_Mf(i)
NEXT
' Save last playlist opened
g_LastPl = playlistPath
e = g_TmpDir + EXE.NAME$ + ".last.pl"
ff = FREEFILE
OPEN e FOR OUTPUT AS #ff
PRINT #ff, playlistPath
CLOSE #ff
' Update header combo
AddToRecentList hDlg, playlistPath
' Get last played media file for this playlist, if any
e = g_TmpDir + FName(playlistPath) + ".m3u"
IF EXISTS(e) THEN
ff = FREEFILE
OPEN e FOR INPUT ACCESS READ LOCK SHARED AS #ff
LINE INPUT #ff, e ' #EXTM3U
LINE INPUT #ff, e ' #EXTINF
LINE INPUT #ff, g_LastMf
CLOSE #ff
END IF
LogMe "- last played media file for this playlist: " + g_LastMf
' New playlist >> propose to start it
ARRAY SCAN g_Mf(), =g_LastMf, TO found
LogMe "- searching file in listview... detected position: " + FORMAT$(found)
IF g_LastMf = "" OR found = 0 THEN
CONTROL SET TEXT hDlg, 3001, "Start playlist"
LISTVIEW SET IMAGE hDlg, 2001, 1, 1 ' play
LISTVIEW SELECT hDlg, 2001, 1
i = MYMSGBOX(hDlg, "Start playlist ?", "", %MB_ICONQUESTION OR %MB_YESNO)
IF i = %IDYES THEN DIALOG POST hDlg, %WM_STARTPL, 0, 0
EXIT SUB
END IF
' Ongoing playlist >> mark read files and current file (where to resume)
CONTROL SET TEXT hDlg, 3001, "Resume playlist"
FOR i = LBOUND(g_Mf) TO UBOUND(g_Mf)
IF i < found THEN
LISTVIEW SET IMAGE hDlg, 2001, i, 2 ' played
ELSEIF i = found THEN
LISTVIEW SET IMAGE hDlg, 2001, i, 1 ' play
LISTVIEW SELECT hDlg, 2001, i
LISTVIEW VISIBLE hDlg, 2001, i
EXIT FOR
END IF
NEXT
i = MYMSGBOX(hDlg, "Resume playlist ?", "", %MB_ICONQUESTION OR %MB_YESNO)
IF i = %IDYES THEN DIALOG POST hDlg, %WM_RESUMEPL, 0, 0
LogMe "LoadPlaylist() finished"
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB AddToRecentList(BYVAL hDlg AS DWORD, BYVAL playlistPath AS STRING)
LOCAL found AS LONG
LOCAL ff AS LONG
IF g_OnUnix THEN
REPLACE g_TmpDir WITH "%TMP%\" IN playlistPath
REPLACE "~\" WITH UNIX_HOME IN playlistPath
ELSE
REPLACE g_TmpDir WITH "%LocalAppData%\" IN playlistPath
END IF
COMBOBOX FIND EXACT hDlg, 1002, 1, PathEnv(playlistPath) TO found
IF found = 0 THEN
ff = FREEFILE
OPEN g_TmpDir + EXE.NAME$ + ".lst" FOR APPEND AS #ff
PRINT #ff, playlistPath
CLOSE #ff
END IF
LoadRecentList hDlg
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
SUB LoadRecentList(hDlg AS DWORD)
LOCAL noproj, found AS LONG
LOCAL ff AS LONG
LOCAL e AS STRING
LogMe "Entering LoadRecentList()"
COMBOBOX RESET hDlg, 1002
e = g_TmpDir + EXE.NAME$ + ".lst"
IF EXISTS(e) THEN
ff = FREEFILE
OPEN e FOR INPUT AS #ff
DO
LINE INPUT #ff, e
IF LEN(e)>0 AND EXISTS(e) THEN
LogMe "- inserting: " + e
COMBOBOX INSERT hDlg, 1002, 1, PathEnv(e)
END IF
LOOP UNTIL EOF(#ff)
CLOSE #ff
COMBOBOX FIND EXACT hDlg, 1002, 1, PathEnv(g_LastPl) TO found
ELSE
LogMe "- no recent list to load!"
COMBOBOX ADD hDlg, 1002, "<none loaded>"
found = 1
END IF
COMBOBOX SELECT hDlg, 1002, found
CONTROL SET TEXT hDlg, 1002, PathEnv(g_LastPl)
LogMe "LoadRecentList() finished"
END SUB
'------------------------------------------------------------------------------
'------------------------------------------------------------------------------
FUNCTION ShowDialog(BYVAL hParent AS LONG) AS LONG
LOCAL lRes AS LONG
LOCAL lSty AS LONG
LOCAL hDlg AS DWORD
LOCAL hIml AS DWORD
DIALOG NEW PIXELS, hParent, EXE.NAME$ + $SPC + $VER, , , 340, 380, %WS_POPUP _
OR %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR _
%WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
%DS_SETFONT OR %WS_CAPTION OR %WS_MINIMIZEBOX, %WS_EX_WINDOWEDGE OR _
%WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
%WS_EX_RIGHTSCROLLBAR, TO hDlg
CONTROL ADD LABEL, hDlg, 1001, "Playlist :", 8, 8, 48, 16, %SS_NOTIFY
CONTROL ADD COMBOBOX, hDlg, 1002, , 56, 5, 230, 18*10, _
%CBS_DROPDOWNLIST, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT
CONTROL ADD BUTTON, hDlg, 1003, "Load", 286, 5, 48, 22, _
%BS_CENTER OR %BS_VCENTER OR %WS_GROUP OR %WS_TABSTOP
CONTROL ADD LISTVIEW, hDlg, 2001, "", 8, 38, 324, 280, %LVS_NOCOLUMNHEADER OR _
%LVS_REPORT OR %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL, %WS_EX_CLIENTEDGE
LISTVIEW INSERT COLUMN hDlg, 2001, 1, "Media file", 320, %SS_LEFT
LISTVIEW GET STYLEXX hDlg, 2001 TO lSty
LISTVIEW SET STYLEXX hDlg, 2001, lSty OR %LVS_EX_FULLROWSELECT OR _
%LVS_EX_GRIDLINES OR %LVS_EX_INFOTIP
CONTROL ADD BUTTON, hDlg, 3001, "Start playlist", 8, 330, 150, 40
CONTROL ADD BUTTON, hDlg, 3002, "Help", 180, 330, 80, 40
' Add status icons
CONTROL ADD IMAGE, hDlg, 4001, "ICO4", 312, 354, 16, 16, %SS_NOTIFY ' eye > VLC listener thread active
CONTROL SHOW STATE hDlg, 4001, %SW_HIDE
CONTROL ADD IMAGE, hDlg, 4002, "ICO5", 312, 336, 16, 16, %SS_NOTIFY ' (!) > VLC last media not found
CONTROL SHOW STATE hDlg, 4002, %SW_HIDE
' Attach play/played imagelist to the listview
IMAGELIST NEW ICON 16, 16, 24, 6 TO hIml
IMAGELIST ADD ICON hIml, "ICO2" ' play
IMAGELIST ADD ICON hIml, "ICO3" ' played
LISTVIEW SET IMAGELIST hDlg, 2001, hIml, 1
DIALOG SET ICON hDlg, "ICO1"
DragAcceptFiles hDlg, %True
DIALOG SHOW MODAL hDlg, CALL ProcDialog TO lRes
FUNCTION = lRes
END FUNCTION
'------------------------------------------------------------------------------