View previous topic :: View next topic |
Author |
Message |
AkulaBig
Joined: 03 Dec 2008 Posts: 274
|
(Separately) Posted: Sat May 10, 2025 15:14 Post subject: |
|
|
Orion9 wrote: | будь я на вашем месте, я сделал бы верхнее меню |
Я уже забыл, верхнее меню это что у нас? |
|
Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 728
|
(Separately) Posted: Tue May 13, 2025 18:30 Post subject: |
|
|
AkulaBig wrote: | Я уже забыл, верхнее меню это что у нас? |
Это то, к чему Гислер за 30 лет не сделал никакого GUI, хотя именно это нужно было делать в первую очередь, а не отмазываться от пользователя неудобным меню "Запуск", которое, как выяснилось, имеет еще и кривую многоязычную поддержку, исправлять которую он теперь не желает. Как-то так.
Думал, что еще не скоро возьмусь за Autorun, но понадобилась одна фича, над которой сейчас работаю. Простенький монитор каталога, чтобы отслеживал изменения и сообщал об удаленных файлах в реальном времени. Попутно сделал кнопку для подсчета времени воспроизведения в каталоге. Что-то подобное делает плагин MediaTime. При желании можно полностью заменить его функционал, если не устраивает одиночное нажатие кнопки:
 Hidden text TOTALCMD#BAR#DATA
62013
%COMMANDER_EXE%
Подсчёт времени воспроизведения
-1
 Hidden text Code: | RegisterCommand 62013 "DurationInfo"
Func DurationInfo(lParam)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & RequestCopyDataInfo("SN")
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo plugin error " & ERROR)
Return
Endif
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
obj.FileName = file
s = obj.GetValue(0) # duration
ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Free(obj)
Return
Endif
Local i, out, files = 0, aFiles = List(), seconds = 0
ShowHint("Подсчёт времени")
# загрузка файлов в массив
ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
aFiles.Text = out
# ShowHint("Обработка " & aFiles.Count & " элементов")
For i = 0 To aFiles.Count - 1
obj.FileName = aFiles[i]
s = obj.GetValue(0,2) # duration -> seconds
If s > 0 Then
seconds += s
files += 1
EndIf
Next
Free(obj)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Каталог: " & name & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Длительность: " & total)
EndFunc |
Функция полностью завязана на плагин TCMediaInfo и его поля, хотя, конечно, можно было и через DllCall сделать, но использование объекта Plugin сводит весь код на Autorun до смешных нескольких строк. |
|
Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 274
|
(Separately) Posted: Tue May 13, 2025 21:40 Post subject: |
|
|
Orion9 wrote: | Функция полностью завязана на плагин TCMediaInfo и его поля, хотя, конечно, можно было и через DllCall сделать |
У меня наоборот, что-то возникло желание переделать пользовательские колонки на Dll, отказавшись от TCMediaInfo. Его использовать только как листер-плагин. Как-бы в моем понимании это даст какую-то упорядоченность.
Только вот навряд-ли Autorun выдержит еще полей 30. Думаю в данном случае как-раз попробовать использовать файл типа hint.txt или массив значений. |
|
Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 728
|
(Separately) Posted: Thu May 15, 2025 00:32 Post subject: |
|
|
AkulaBig wrote: | отказавшись от TCMediaInfo |
Имхо, TCMediaInfo один из лучших плагинов, не понятно, зачем от него отказываться. Я наоборот хотел с ним лучше разобраться, т.к. он у меня в подвисшем состоянии остался.
AkulaBig wrote: | Только вот навряд-ли Autorun выдержит еще полей 30. |
Да поля-то он, наверное, выдержит, только все-равно не понятно, зачем заменять один плагин другим. В скорости, например, от этого вряд ли получится выиграть, я как раз в этом убедился сейчас.
Пришлось переделать функцию подсчета, убрав из неё получение списка через ProcessExecGetOutput, т.к. этот вариант не работает с UNC-путями. Попутно сделал вызов через DllCall и расширил функционал. Сейчас вызов с ALT делает подсчет через плагин TCMediaInfo.wdx, а простой вызов через MediaInfo.dll. Поскольку MediaInfo.dll обрабатывает все файлы (даже те, которые не-медиа, что замедляет работу), пришлось добавить фильтр. При включеном CapsLock фильтр отключается. Вызов с CTRL ограничивает глубину каталога до первого уповня. SHIFT - выводит в окно отладчика информацию о пропущенных элементах.
 Hidden text Code: | RegisterCommand 62013 "Duration"
Func Duration(lParam)
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime()
Local b_Ctrl = IsPressed(0x11), b_Shift = IsPressed(0x10), b_Alt = IsPressed(0x12)
Local b_Caps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & name
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local hMI = 0
Static sLib = "MediaInfo" & (auX64 ? "" : "_i386") & ".dll", _
hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs\" & sLib, "ptr")
Static sExt = ".aac .ac3 .aif .aiff .aifc .afc .ape .au .snd .cda .dsf .dts .dtswav .dtshd .dtsma .eac3 .flac .fla _
.m1a .m2a .mka .mpa .mp1 .mp2 .mp3 .mp4 .m4a .m4b .m4r .mod .mpc .mp+ .mpp .ogg .ogg .oga .ogx .ogg _
.ra .spx .opus .qoa .svx .8svx .tak .tta .wav .wave .w64 .bwf .rf64 .wma .wv .avi .wmv .wmp .wm .asf _
.mpg .mpeg .mpe .m1v .m2v .mpv2 .mp2v .ts .tp .tpr .trp .vob .ifo .ogm .ogv .mp4 .m4v .m4p .m4b .3gp _
.3gpp .3g2 .3gp2 .mkv .rm .ram .rmvb .rpm .flv .swf .mov .qt .amr .nsv .dpg .m2ts .m2t .mts .dvr-ms _
.k3g .skm .evo .nsr .amv .divx .webm .wtv .f4v .mxf"
If Not b_Alt Then
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
hMI = DllCall(sLib & '\MediaInfo_New', "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo failed to create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo plugin error " & ERROR)
Return
Endif
EndIf
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
If b_Alt Then
obj.FileName = file
s = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", file, "uint") <> 1 Then
Return ShowHint("MediaInfo_Open failed to open file " & file)
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration/String3", "int", 1, "int", 0, "wstr")
EndIf
Return ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Endif
Local i, out, dirs = 0, files = 0, errs = 0, aFiles = List(), seconds = 0
Local depth = (b_Ctrl ? 1 : 0)
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "yes" : "no") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Подсчёт времени")
b_Win = false
# загрузка файлов в массив
If b_Win Then
#ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
#aFiles.Text = out
Else
ListDirectory(file, aFiles, depth)
EndIf
# ShowHint("Обработка " & aFiles.Count & " элементов")
For i = 0 To aFiles.Count - 1
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If b_Shift Then OutputDebugString("Duration:Directory:" & aFiles[i])
Continue
EndIf
If b_Alt Then
obj.FileName = aFiles[i]
s = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not b_Caps Then
If Not StrPos(sExt, '.' & ext) Then
If b_Shift Then OutputDebugString("Duration:Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", aFiles[i], "uint") <> 1 Then
errs += 1
If b_Shift Then OutputDebugString("Duration:Error:" & aFiles[i])
Continue
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr")
EndIf
If s > 0 Then
seconds += s
files += 1
Else
If b_Shift Then OutputDebugString("Duration:Empty:" & aFiles[i])
EndIf
If IsPressed(0x11) And IsPressed(0x12) Then
ShowHint((b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"CapsLock: " & (b_Caps ? "yes" : "no") & auCRLF & _
"Depth: " & depth & auCRLF & _
"File: " & i & " of " & aFiles.Count & auCRLF & _
aFiles[i])
EndIf
Next
If b_Alt Then Free(obj)
If hMI <> 0 Then DllCall(sLib & '\MediaInfo_Delete', "Ptr", hMI)
seconds = Floor(seconds / 1000)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Папка: " & name & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Ошибки DLL: " & errs & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Длительность: " & total & auCRLF & _
"Powered by " & (b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & Round(GetUptime() - T1, 3))
Free(aFiles)
EndFunc
Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "\" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "\" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "\" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFunc |
|
|
Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 274
|
(Separately) Posted: Thu May 15, 2025 07:09 Post subject: |
|
|
Orion9 wrote: | он у меня в подвисшем состоянии остался |
В этом все и дело. Если зайдете в его тему, увидите, что мы там обсуждали некоторые проблемы. Не все гладко с файлом настройки. Вот и получается, что либо там разбираться с настройками, либо здесь пойти по уже проторенной дорожке. Ну а листер-плагину TCMediaInfo альтернативы нет. |
|
Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 728
|
(Separately) Posted: Thu May 15, 2025 14:06 Post subject: |
|
|
AkulaBig wrote: | либо там разбираться с настройками, либо здесь пойти по уже проторенной дорожке |
Так ведь плагин TCMediaInfo и есть проторенная дорожка. Вопрос здесь больше в изучении самой MediaInfo.dll и её возможностей, чтобы лучше понимать что и в каких случаях выводить. А для этого придётся глубже копнуть в форматы файлов и их устройство, а не только в изучение настроек XML.
Откинул меня подсчёт времени воспроизведения, но вроде доделал как надо, хотя нужно больше тестов. Сейчас повторное нажатие на кнопку прерывает операцию, как и комбинация Win + ESC. Зажатие CTRL + ALT во время подсчёта показывает прогресс операции в подсказке. Обнаружил одну неприятную проблему. MediaInfo.dll может зависнуть на некоторых файлах и повесить ТС. Пока мне попался один такой файл, который нормально проигрывается, но видимо с тегами что-то не так. Foobar при проверке целостности пишет: Warning: Multiple ID3v2 tags encountered, item decoded with minor problems. Программа Mp3Tag пишет: ID3v2.3 ERROR: MP3 header parse error. В остальном проблем больше не заметил. Последняя версия кнопки:
 Hidden text Code: | RegisterCommand 62013 "Duration"
Global MI_DURATION = 0, MI_BREAK = false
Func Duration(lParam)
If MI_DURATION > 0 Then
MI_BREAK = true
Sleep(250)
Return
EndIf
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime(), T2 = 0
Local b_Ctrl = IsPressed(0x11), b_Shift = IsPressed(0x10), b_Alt = IsPressed(0x12)
Local b_Caps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & name
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local hMI = 0
Static sLib = "MediaInfo" & (auX64 ? "" : "_i386") & ".dll", _
hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs\" & sLib, "ptr")
Static sExt = ".aac .ac3 .aif .aiff .aifc .afc .ape .au .snd .cda .dsf .dts .dtswav .dtshd .dtsma .eac3 _
.flac .fla .m1a .m2a .mka .mpa .mp1 .mp2 .mp3 .mp4 .m4a .m4b .m4r .mod .mpc .mp+ .mpp _
.oga .ogx .ogg .ra .spx .opus .qoa .svx .8svx .tak .tta .wav .wave .w64 .bwf .rf64 .wma .wv _
.avi .wmv .wmp .wm .asf .mpg .mpeg .mpe .m1v .m2v .mpv2 .mp2v .ts .tp .tpr .trp .vob .ifo _
.ogm .ogv .mp4 .m4v .m4p .m4b .3gp .3gpp .3g2 .3gp2 .mkv .rm .ram .rmvb .rpm .flv .swf .mov _
.qt .amr .nsv .dpg .m2ts .m2t .mts .dvr-ms .k3g .skm .evo .nsr .amv .divx .webm .wtv .f4v .mxf"
If Not b_Alt Then
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
hMI = DllCall(sLib & '\MediaInfo_New', "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo.dll failed to create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo.wdx plugin error " & ERROR)
Return
Endif
EndIf
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
If b_Alt Then
obj.FileName = file
s = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", file, "uint") <> 1 Then
Return ShowHint("MediaInfo.dll failed to open file " & file)
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration/String3", "int", 1, "int", 0, "wstr")
EndIf
Return ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Endif
ShowHint("Загрузка")
MI_BREAK = false
MI_DURATION = 1
Local i, out, dirs = 0, files = 0, errs = 0, aFiles = List(), seconds = 0, b_Hint = 0
Local depth = (b_Ctrl ? 1 : 0)
b_Win = false
# загрузка файлов в массив
If b_Win Then
#ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
#aFiles.Text = out
Else
ListDirectory(file, aFiles, depth)
EndIf
If aFiles.Count > 1 Then
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
For i = 0 To aFiles.Count - 1
#OutputDebugString("Duration:File:" & aFiles[i])
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If b_Shift Then OutputDebugString("Duration:Directory:" & aFiles[i])
Continue
EndIf
If b_Alt Then
obj.FileName = aFiles[i]
s = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not b_Caps Then
If Not StrPos(sExt, '.' & ext) Then
If b_Shift Then OutputDebugString("Duration:Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", aFiles[i], "uint") <> 1 Then
errs += 1
If b_Shift Then OutputDebugString("Duration:Error:" & aFiles[i])
Continue
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr")
EndIf
If s > 0 Then
seconds += s
files += 1
Else
If b_Shift Then OutputDebugString("Duration:Empty:" & aFiles[i])
EndIf
If MI_BREAK = true Or (IsPressed (0x11) And IsPressed (0x1B)) Then
ShowHint("Операция прервана")
Sleep(700)
Break
EndIf
If IsPressed(0x11) And IsPressed(0x12) Then
b_Hint += 1
If Round(GetUptime() - T2, 0) > 500 Then
ShowHint( _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
"Depth: " & depth & auCRLF & _
"File: " & i & " of " & aFiles.Count _
)
T2 = GetUptime()
EndIf
Else
If b_Hint > 0 Then
b_Hint = 0
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
EndIf
Next
If b_Alt Then Free(obj)
If hMI <> 0 Then DllCall(sLib & '\MediaInfo_Delete', "Ptr", hMI)
MI_BREAK = false
MI_DURATION = 0
seconds = Floor(seconds / 1000)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Папка: " & name & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Ошибки DLL: " & errs & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Время: " & Chr(0x2211) & " "& total & auCRLF & _
"Powered by " & (b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & Round(GetUptime() - T1, 3))
Free(aFiles)
EndFunc
Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "\" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "\" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "\" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFunc |
|
|
Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 274
|
(Separately) Posted: Thu May 15, 2025 15:05 Post subject: |
|
|
Orion9 wrote: | придётся глубже копнуть в форматы файлов и их устройство |
Копай, не копай. Раз тэги заполняют люди, все равно не угадаешь с заполненными полями. Собственно ведь поля тэгов для всех этих расширений одинаковы.
Orion9 wrote: | а не только в изучение настроек XML |
Дак это еще один язык программирования нестандартный. Получается язык Autorun надо изучить и язык TCMediaInfo. Для молодых и умных может и нет проблем. А у нас время ограничено. Не очень интересно этим заниматься. |
|
Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 728
|
(Separately) Posted: Fri May 16, 2025 00:32 Post subject: |
|
|
AkulaBig wrote: | Собственно ведь поля тэгов для всех этих расширений одинаковы |
MediaInfo.dll больше, чем просто тэги. Гораздо важнее техническая информация, которую дает эта библиотека. И если задача просто вывести некоторые поля из MediaInfo.dll, то, думаю, TCMediaInfo.wdx вполне для этого достаточно. А то, что там используется свой язык, так это только гибкости добавляет, на мой взгляд.
Все, готов монитор. Очень простенький, конечно, но зато рабочий.
Отдельный модуль:
 Monitor.aucfg Code: | Global DIR_MONITOR1 = "D:\Temp\Test"
Global DIR_MONITOR2 = COMMANDER_PATH & "\Ini"
Global DIR_MONITOR3 = "\\Server\Share\Test"
RegisterCommand 81000 "DirMonitorCmd"
RegisterCommand 81001 "DirMonitorMenu"
Func DirMonitorCmd(lParam)
DirMonitor(DIR_MONITOR1, 0)
EndFunc
Func DirMonitor(FolderName, FolderDepth)
Local sLog, sChanges, sOps
# счётчик, лог, снимок, каталог
Static c = 0, sLogFile = TEMP & "\tc_dir_monitor.log", _
sMenuFile = TEMP & "\tc_dir_changes.log", _
sSnapFile = TEMP & "\tc_dir_snap.lst", sDir = FolderName
# список файлов и сохраненный список
Static aFiles = List(), aSnap = List()
# список новых и удаленных файлов
Static aNewFiles = List(), aDelFiles = List()
c += 1
# смена каталога в текущей сессии
If sDir <> FolderName Then
c = 1
sDir = FolderName
aSnap.Count = 0
aFiles.Count = 0
aNewFiles.Count = 0
aDelFiles.Count = 0
EndIf
# первый запуск монитора
If c = 1 Then
sLog &= auCRLF & auCRLF
sLog &= LogFormat(1, "Мониторинг каталога " & sDir)
If FileExist(sSnapFile) Then
sLog &= LogFormat(1, "Загрузка снимка " & sSnapFile)
aSnap.LoadFromFile(sSnapFile)
# проверка снимка
If aSnap.Count > 0 And Not StrPos(aSnap[0], sDir) Then
sLog &= LogFormat(1, "Снимок не содержит предыдущих записей")
aSnap.Count = 0
Endif
If aSnap.Count > 0 Then
sLog &= LogFormat(1, "Снимок загружен: " & aSnap.Count & " элементов")
EndIf
Else
sLog &= LogFormat(1, "Снимок не обнаружен")
EndIf
Endif
sLog &= LogFormat(1, "Проверка N " & c)
# каталог не доступен
If Not FileExist(sDir) Then
sLog &= LogFormat(1, "Каталог не доступен.")
Return
Endif
Local out
# загрузка файлов в массив
aFiles.Count = 0
ListDirectory(sDir, aFiles, FolderDepth)
sLog &= LogFormat(1, "Файлы взяты в массив: " & aFiles.Count & " элементов")
# каталог пустой
If aFiles.Count = 0 Or Not StrPos(aFiles[0], sDir) Then
sLog &= LogFormat(1, "Каталог не содержит записей.")
Endif
# обработка предыдущего списка
Local a = 0, d = 0
If aSnap.Count > 0 Then
For i = 0 To aSnap.Count - 1
If aFiles.IndexOf(aSnap[i]) = -1 Then
aDelFiles.Add(aSnap[i])
sLog &= LogFormat(1, "Файл удален " & aSnap[i])
d += 1
sChanges &= LogFormat(1, " [-] " & FileGetName(aSnap[i]))
sOps &= FileGetName(aSnap[i]) & auCRLF
EndIf
Next
For i = 0 To aFiles.Count - 1
If aSnap.IndexOf(aFiles[i]) = -1 Then
aNewFiles.Add(aFiles[i])
sLog &= LogFormat(1, "Файл добавлен " & aFiles[i])
a += 1
sChanges &= LogFormat(1, " [+] " & FileGetName(aFiles[i]))
sOps &= FileGetName(aFiles[i]) & auCRLF
EndIf
Next
EndIf
# новое состояние списка
aSnap = aFiles.Clone()
aSnap.SaveToFile(TEMP & "\tc_dir_snap.lst")
# фиксирование изменений
If a > 0 Or d > 0 Then
FileAppend(sMenuFile, sChanges)
Local sMsg
If d > 0 Then sMsg &= LogFormat(0, "Удалено: " & d)
If a > 0 Then sMsg &= LogFormat(0, "Добавлено: " & a)
sMsg &= sOps
sLog &= LogFormat(1, "Изменения в каталоге:")
sLog &= LogFormat(1, "Удалено: " & d)
sLog &= LogFormat(1, "Добавлено: " & a)
NotifyInfoMessage(0, sMsg, "Монитор каталога", NIIF_INFO)
Else
sLog &= LogFormat(1, "Нет изменений в каталоге")
Endif
FileAppend(sLogFile, sLog)
EndFunc
Func LogFormat(DateTime, LogText)
Local txt
Switch DateTime
Case 0
txt = StrFormat("%s\r\n", LogText)
Case 1
txt = StrFormat("%s %s %s\r\n", Date(), Time(), LogText)
Case 2
txt = StrFormat("%s %s\r\n", Date(), LogText)
Case 3
txt = StrFormat("%s %s\t%s\r\n", Date(), Time(), LogText)
Else
txt = StrFormat("%s %s\r\n", Time(), LogText)
EndSwitch
Return txt
EndFunc
#RunThread ThreadDirMonitor
Func ThreadDirMonitor()
While 1
#Sleep(180*60*1000)
Sleep(5000)
DirMonitor(DIR_MONITOR1, 0)
Wend
EndFunc
Func DirMonitorMenu(lParam)
ShowPopupMenu /D /F "CreateDirMonitorMenu"
EndFunc
Func CreateDirMonitorMenu()
Local txt, ops
Local buf = FileRead(TEMP & "\tc_dir_changes.log")
If buf <> "" Then
Local aLog = List(), i = 0, j, date = Date()
aLog.Text = buf
For j = aLog.Count - 1 To 0 Step -1
i += 1
ops &= 'MENUITEM "' & aLog[j] & '", ' & _
(StrPos(aLog[j], date) > 0 ? "em_dir_monitor_new" : "em_dir_monitor_old") & auCRLF
If i > 20 Then Break
Next
Free(aLog)
Else
ops = 'MENUITEM "Empty", 100000'
EndIf
txt = 'MENUITEM "Журнал монитора...", em_dir_monitor_log' & auCRLF & _
'MENUITEM "Журнал операций...", em_dir_monitor_ops' & auCRLF & _
'MENUITEM SEPARATOR' & auCRLF
txt &= ops & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Перейти к файлу монитора...", em_dir_monitor_2log' & auCRLF
txt &= 'MENUITEM "Перейти к файлу операций...", em_dir_monitor_2ops' & auCRLF
Return txt
EndFunc |
Дополнительные функции:
 ListDirectory Code: | Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "\" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "\" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "\" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFunc |
 NotifyInfoMessage Code: | # иконки окна уведомлений
Const NIIF_NONE = 0x00000000, _
NIIF_INFO = 0x00000001, _
NIIF_WARNING = 0x00000002, _
NIIF_ERROR = 0x00000003, _
NIIF_USER = 0x00000004
# без звука
Const NIIF_NOSOUND = 0x00000010
# большая иконка
Const NIIF_LARGE_ICON = 0x00000020
# сообщения окна уведомлений
Const NIN_BALLOONSHOW = 0x402, _
NIN_BALLOONHIDE = 0x403, _
NIN_BALLOONTIMEOUT = 0x404, _
NIN_BALLOONUSERCLICK = 0x405, _
NIN_POPUPOPEN = 0x406, _
NIN_POPUPCLOSE = 0x407
# флаги структуры
Const NIF_MESSAGE = 0x00000001, _
NIF_ICON = 0x00000002, _
NIF_TIP = 0x00000004, _
NIF_STATE = 0x00000008, _
NIF_INFO = 0x00000010
SetMessageAction /P 99998 TrayNotifyInfo
# служебная иконка
Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
# освобождение невидимой иконки
If lParam = NIN_BALLOONUSERCLICK or lParam = NIN_BALLOONTIMEOUT Then
NotifyIcon("delete", 1010)
EndIf
EndFunc
Func NotifyInfoMessage(Icon, InfoText, InfoTitle = "Autorun", InfoType = 0)
Local dwFlags = 0
Local buf = Buffer(auPtrSize = 4 ? 956 : 976)
Local hIco = 0, tc = COMMANDER_PATH & "\TOTALCMD.EXE"
hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", tc, "uint", 0, "ptr")
If Icon Then
dwFlags = BitOR(NIF_MESSAGE, NIF_ICON, NIF_INFO)
Else
dwFlags = BitOR(NIF_MESSAGE, NIF_STATE, NIF_ICON, NIF_INFO)
Endif
buf.Zero()
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", 1010, _
"uint", dwFlags, _
"uint", 99998)
buf.SetNum(32, "ptr", hIco)
buf.SetNum(296, "dword", 1, _
"dword", 1)
Else
buf.SetNum(0, "dword", buf.size, _
"hwnd", AUTORUN_TCHANDLE, _
"uint", 1010, _
"uint", dwFlags, _
"uint", 99998, _
"ptr", hIco) )
buf.SetNum(280, "dword", 1, _
"dword", 1)
EndIf
Local offset = (auX64 ? 40 : 24) + 256 + 4 + 4
buf.SetStr(StrLeft(InfoText, 199) & Chr(0), offset)
If StrLen(InfoTitle) > 0 Then
buf.SetStr(StrLeft(InfoTitle, 47) & Chr(0), offset + 512 + 4)
EndIf
If InfoType > 0 Then
buf.SetNum(offset + 512 + 4 + 128, "dword", InfoType)
EndIf
Local Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr)
If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco)
Free(buf)
Return Result
EndFunc |
Последняя функция используется для показа системных сообщений без отображения значка в трее, но за ней были замечены проблемы на Win8.1 и Win10. Лучше взять доработанный пример из справки от Loopback, у меня времени не хватило, чтобы вставить его в модуль.
Функция следит за удаленными и добавленными файлами и создает лог во временном каталоге. Также в %TEMP% создаются еще два файла, в которых хранится предыдущий снимок и журнал операций. Последний открывается в кнопке-меню по коду 81001. Чтобы украсить меню значками, используются em_ команды:
Code: | [em_dir_monitor_new]
button=%COMMANDER_PATH%\Ini\NewsBar\notify-yes.ico
[em_dir_monitor_old]
button=%COMMANDER_PATH%\Ini\NewsBar\notify-no.ico
[em_dir_monitor_log]
button=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
cmd=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
param=tc_dir_monitor.log
path=%TEMP%
[em_dir_monitor_ops]
button=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
cmd=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
param=tc_dir_changes.log
path=%TEMP%
[em_dir_monitor_2log]
button=%COMMANDER_EXE%,0
cmd=CD %TEMP%\tc_dir_monitor.log
[em_dir_monitor_2ops]
button=%COMMANDER_EXE%,0
cmd=CD %TEMP%\tc_dir_changes.log |
Простой способ запустить монитор в отдельном потоке:
Code: | RunThread ThreadDirMonitor
Func ThreadDirMonitor()
While 1
Sleep(180*60*1000)
DirMonitor(DIR_MONITOR1, 0)
Wend
EndFunc |
Раз в полчаса каталог DIR_MONITOR1 будет проверяться и изменения будут логироваться в файлы, сообщения об изменениях будут отображаться в системных уведомлениях. |
|
Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 274
|
(Separately) Posted: Fri May 16, 2025 06:12 Post subject: |
|
|
Orion9 wrote: | И если задача просто вывести некоторые поля из MediaInfo.dll, то, думаю, TCMediaInfo.wdx вполне для этого достаточно. |
Я выше написал. Там некоторые поля неправильно выводятся. Надо править его файл настройки xml. |
|
Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 728
|
(Separately) Posted: Fri May 16, 2025 11:49 Post subject: |
|
|
AkulaBig wrote: | Я выше написал. Там некоторые поля неправильно выводятся. |
У меня не было времени посмотреть, и сейчас тоже не могу, так как много разных дел появилось, но еще вернусь к этому позже.
Обнаружил первый небольшой косячок, забыл добавить FileAppend(sLogFile, sLog) перед Return:
Code: | # каталог не доступен
If Not FileExist(sDir) Then
sLog &= LogFormat(1, "Каталог не доступен.")
FileAppend(sLogFile, sLog)
Return
Endif |
Это не важно, т.к. функцией вряд ли кто-то будет пользоваться в таком виде, я скинул данный код на случай новых идей и решений. |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|