Advertisement
Guest User

EventGhost MPC-HC64

a guest
Jan 7th, 2025
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.14 KB | Software | 0 0
  1. # this try/except routine is done because the information that is generated
  2. # in a Python script is persistent between runs. Whats this means is that
  3. # anything that is created in a python script when the script gets run a
  4. # second, third, fourth... the objects created the first time are available to
  5. # every run thereafter. So if you have any objects created that are static and
  6. # do not change between runs then there is no need to make them over again.
  7. # To test for this we simply use one of those object names that are static.
  8. # if the object exists it will pass right on by. if it oes not it will
  9. # generate an error that we catch in the except portion of thee code block.
  10. # And that is where we will then create all of the static objects
  11.  
  12.  
  13. # adjustable set between 0 and 255
  14. MAX_TRANSPARENT = 255
  15.  
  16. import time
  17.  
  18. start = time.time()
  19. try:
  20. user32
  21. except NameError:
  22. import wx
  23. import datetime
  24. import time
  25. import threading
  26. import ctypes
  27. from ctypes.wintypes import (
  28. BOOL,
  29. LONG,
  30. UINT,
  31. POINT,
  32. RECT,
  33. HWND,
  34. LPARAM,
  35. DWORD
  36. ) # NOQA
  37.  
  38. from eg.WinApi import (
  39. GetWindowText,
  40. GetTopLevelWindowList,
  41. GetProcessName
  42. ) # NOQA
  43.  
  44. from eg.WinApi.Dynamic import (
  45. SetWindowPos,
  46. SWP_FRAMECHANGED,
  47. SWP_NOACTIVATE,
  48. SWP_NOOWNERZORDER,
  49. SWP_SHOWWINDOW,
  50. )
  51.  
  52.  
  53. HWND_FLAGS = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED
  54.  
  55. GWL_STYLE = -16
  56. GWL_EXSTYLE = -20
  57. WS_BORDER = 0x00800000
  58. WS_DLGFRAME = 0x00400000
  59. WS_THICKFRAME = 0x00040000
  60. WS_EX_WINDOWEDGE = 0x00000100
  61. WS_POPUP = 0x80000000
  62. WS_EX_TOPMOST = 0x00000008
  63.  
  64. PID = DWORD
  65. user32 = ctypes.windll.User32
  66.  
  67. # DWORD GetWindowThreadProcessId(
  68. # HWND hWnd,
  69. # LPDWORD lpdwProcessId
  70. # );
  71. _GetWindowThreadProcessId = user32.GetWindowThreadProcessId
  72. _GetWindowThreadProcessId.restype = DWORD
  73.  
  74. # LONG GetWindowLongW(
  75. # HWND hWnd,
  76. # int nIndex
  77. # );
  78.  
  79. _GetWindowLong = user32.GetWindowLongW
  80. _GetWindowLong.restype = LONG
  81.  
  82. # HWND GetActiveWindow(
  83. #
  84. # );
  85. _GetActiveWindow = user32.GetActiveWindow
  86. _GetActiveWindow.restype = HWND
  87.  
  88. BAR_TEMPLATE = \'[{bars}{remaining}] - {percent:.2f}%\'
  89. ELAPSED_TOTAL_TEMPLATE = \'Elapsed: {elapsed} / Total: {duration}\'
  90. OSD_TEMPLATE = \'{title}\
  91. \
  92. {bar}\
  93. {elapsed_total}\'
  94. osd_frame = eg.plugins.EventGhost.actions[\'ShowOSD\'].osdFrame
  95. _old_show_osd = osd_frame.ShowOSD
  96. _old_on_timeout = osd_frame.OnTimeout
  97.  
  98. eg.globals.fade_in_event = threading.Event()
  99. eg.globals.fade_out_event = threading.Event()
  100.  
  101.  
  102. stop = time.time()
  103.  
  104. ##print \'imports and setup\', (stop - start) * 1000, \'milliseconds\'
  105.  
  106. start = time.time()
  107. # OK so I removed the euse of the eg.WindowMatcher.
  108. # it is a horribly slow thing to use and since we are only looking to see
  109. # if a process is running or not we use GetTopLevelWindowList which returns
  110. # the handles for the base window class of an application. then we ask windows
  111. # to get us the process id (pid) for one of the handles in the returned list.
  112. # Then we use that pid to get the process name. and we match that process name
  113. # up with the one we are looking for.
  114.  
  115. handles = GetTopLevelWindowList(False)
  116.  
  117. stop = time.time()
  118.  
  119. ##print \'GetTopLevelWindowList\', (stop - start) * 1000, \'milliseconds\'
  120.  
  121. start = time.time()
  122. # OK so I added some code to locate which instance of mpc to use if more then
  123. # one is running.
  124. # I elected to do some crafty coding with this. What happens is after the the
  125. # window handles are found I then query the Windows API to get thee styles of
  126. # the window. i check for specific markers like if the window has a border and
  127. # if the window is set to be the topmost window as these are things that get
  128. # turned on/off when an application goes into a fullscreen mode. at the same
  129. # time I am also checking for a copy of mpc that is the active window. I do
  130. # this to cover my bases, if there is more then a single active copy and none
  131. # of them are set to full screen it is going to choose the one that is active
  132. # (has focus). if there is a fullscreen copy running and a second. and the
  133. # second is active the fullscreen is going to be the one used.
  134.  
  135. for handle in handles[:]:
  136. pid = PID()
  137. _GetWindowThreadProcessId(HWND(handle), ctypes.byref(pid))
  138.  
  139. process_name = GetProcessName(pid.value)
  140.  
  141. # we check the process name of the window. if it does not match then we
  142. # remove it form the list.
  143. if process_name != \'mpc-hc64.exe\':
  144. handles.remove(handle)
  145.  
  146. stop = time.time()
  147.  
  148. ##print \'_GetWindowThreadProcessId\', (stop - start) * 1000, \'milliseconds\'
  149.  
  150. # if there are no windows found then we want to stop the macro from running and
  151. # exit the script
  152.  
  153. if not handles:
  154. handle = None
  155. eg.StopMacro()
  156. eg.Exit()
  157.  
  158.  
  159. handle = None
  160. # I removed the use of eg.globals.WindowsState as a mechanism for checking if
  161. # the app is in fullscreen mode. Because this is one of the things we are
  162. # looking for when we pick the window to use we no longer need to depend on
  163. # an outside source to determine the window state. So you can remove that from
  164. # your tree if you want.
  165. is_fullscreen = False
  166.  
  167.  
  168. start = time.time()
  169. for hwnd in handles:
  170. # getting the windows styles and extended styles.
  171. style = _GetWindowLong(HWND(hwnd), GWL_STYLE)
  172. style_ex = _GetWindowLong(HWND(hwnd), GWL_EXSTYLE)
  173.  
  174. # checking the styles for specific markers.
  175. if (
  176. not style & WS_BORDER and
  177. not style & WS_DLGFRAME and
  178. not style & WS_THICKFRAME and
  179. not style_ex & WS_EX_WINDOWEDGE and
  180. style & WS_POPUP and
  181. style_ex & WS_EX_TOPMOST
  182. ):
  183. # if there are 2 copies of mpc running and both are fullscreen then
  184. # we are going to use the one that is active
  185. if is_fullscreen is False:
  186. handle = hwnd
  187. is_fullscreen = True
  188. elif _GetActiveWindow() == hwnd:
  189. handle = hwnd
  190. is_fullscreen = True
  191.  
  192. # if there is no full screen one found already and this window is active
  193. # then we seet it into place
  194. elif handle is None and _GetActiveWindow() == hwnd:
  195. handle = hwnd
  196. is_fullscreen = False
  197.  
  198. stop = time.time()
  199.  
  200. ##print \'is fullscreen\', (stop - start) * 1000, \'milliseconds\'
  201.  
  202.  
  203. # fallback if something does not work properly in the code.
  204. if handle is None:
  205. handle = handles[0]
  206.  
  207. start = time.time()
  208. window_text = GetWindowText(handle)
  209. stop = time.time()
  210.  
  211. ##print \'GetWindowText\', (stop - start) * 1000, \'milliseconds\'
  212.  
  213. # I removed the use of re and did a simple trial and error using a for loop
  214. # with an else statement.
  215. # If i split a string on a value and that value is not n the string it is
  216. # going to return a list with the original string at index 0. So the list
  217. # only las a length of 1. if it did have the value in it the list would have a
  218. # length greater then 1. and we use that to break the loop. This will cause
  219. # the else to not get run.
  220.  
  221. start = time.time()
  222. for item in (".mkv", ".mp4", ".avi", ".ogm"):
  223. window_text = window_text.split(item)
  224. if len(window_text) > 1:
  225. break
  226. window_text = window_text[0]
  227. else:
  228. window_text = window_text.split(\'.\')
  229.  
  230. stop = time.time()
  231.  
  232. ##print \'windows text evaluation\', (stop - start) * 1000, \'milliseconds\'
  233.  
  234. title = window_text[0]
  235.  
  236. print \'value of time.time() is \', + time.time()
  237.  
  238. start = time.time()
  239.  
  240. _elapsed, _remaining, _duration = eg.plugins.MediaPlayerClassic.GetTimes()
  241. print \'value of times: _elapsed:\', _elapsed, \'; _remaining:\', _remaining, \'duration;\', _duration
  242.  
  243. # I removed all of that math involved in trying to get the seconds in
  244. # favor of using time.strptime and datetime.timedelta
  245. # time.strptime will take a string formatted time representation and turn it
  246. # into a python object for us. we simply have to provide details as to how the
  247. # string is formatted. you can get more information on the identifiers here
  248. # http://strftime.org/
  249. # once we have that object which only does the simple
  250. # conversion to hours minutes seconds we need to create another object that
  251. # does the match for us and will return the total seconds
  252.  
  253. stop = time.time()
  254. ##print \'eg.plugins.MediaPlayerClassic.GetTimes\', (stop - start) * 1000, \'milliseconds\'
  255.  
  256. start = time.time()
  257. while _elapsed.count(\':\') < 2:
  258. _elapsed = \'00:\' + _elapsed
  259. while _remaining.count(\':\') < 2:
  260. _remaining = \'00:\' + _remaining
  261. while _duration.count(\':\') < 2:
  262. _duration = \'00:\' + _duration
  263.  
  264. elapsed = time.strptime(_elapsed, \'%H:%M:%S\')
  265. elapsed = datetime.timedelta(
  266. hours=elapsed.tm_hour,
  267. minutes=elapsed.tm_min,
  268. seconds=elapsed.tm_sec
  269. )
  270.  
  271. remaining = time.strptime(_remaining, \'%H:%M:%S\')
  272. remaining = datetime.timedelta(
  273. hours=remaining.tm_hour,
  274. minutes=remaining.tm_min,
  275. seconds=remaining.tm_sec
  276. )
  277.  
  278. duration = time.strptime(_duration, \'%H:%M:%S\')
  279. duration = datetime.timedelta(
  280. hours=duration.tm_hour,
  281. minutes=duration.tm_min,
  282. seconds=duration.tm_sec
  283. )
  284.  
  285. stop = time.time()
  286. ##print \'time evaluation\', (stop - start) * 1000, \'milliseconds\'
  287.  
  288. # heere we do a test to see if elapsed has any seconds to it. if iit does
  289. # that means the video is playing and to generate the osd
  290. if elapsed.total_seconds():
  291. def fade_in():
  292. beg = time.time()
  293. for i in range(MAX_TRANSPARENT):
  294. if eg.globals.fade_in_event.isSet():
  295. break
  296. osd_frame.SetTransparent(i)
  297. eg.globals.fade_in_event.wait(0.01)
  298.  
  299. osd_frame.ShowOSD = _old_show_osd
  300. end = time.time()
  301.  
  302. ##print \'fade in\', (end - beg) * 1000, \'milliseconds\'
  303.  
  304.  
  305. def fade_out():
  306. beg = time.time()
  307.  
  308. for i in range(MAX_TRANSPARENT, 0, -255):
  309. if eg.globals.fade_out_event.isSet():
  310. break
  311. osd_frame.SetTransparent(i)
  312. eg.globals.fade_out_event.wait(0.01)
  313.  
  314. _old_on_timeout()
  315. osd_frame.OnTimeout = _old_on_timeout
  316. end = time.time()
  317.  
  318. ##print \'fade out\', (end - beg) * 1000, \'milliseconds\'
  319.  
  320. def show_osd(*args, **kwargs):
  321. args = list(args)
  322. args[7] += MAX_TRANSPARENT * 0.01
  323.  
  324. eg.globals.fade_out_event.set()
  325. eg.globals.fade_in_event.clear()
  326.  
  327. osd_frame.SetTransparent(0)
  328. _old_show_osd(*args, **kwargs)
  329.  
  330. fade_in()
  331.  
  332. def on_timeout():
  333. eg.globals.fade_in_event.set()
  334. eg.globals.fade_out_event.clear()
  335. fade_out()
  336.  
  337.  
  338. osd_frame.ShowOSD = show_osd
  339. osd_frame.OnTimeout = on_timeout
  340.  
  341. # instead of having to calls to ShowOSD we can set the parameters we want
  342. # to pass to ShowOSD into a variable you name the variable the same for
  343. # Fullscreen and not Fullscreen and set the parameters for each variation
  344. # then when we call ShowOSD the proper set of parameters will be passed
  345.  
  346. #eg.plugins.EventGhost.ShowOSD(u\'Ahira no Sora\', u\'0;-96;0;0;0;700;0;0;0;0;3;2;1;49;Consolas\', (255, 255, 255), (0, 0, 0), 4, (0, 0), 1, 3.0, None)
  347. #eg.plugins.EventGhost.ShowOSD(u\'Ahira no Sora\', u\'0;-96;0;0;0;400;255;0;0;0;3;2;1;49;Consolas\', (255, 255, 255), (0, 0, 0), 4, (0, 0), 1, 3.0, None)
  348.  
  349. print \'MPC Window State is \', eg.globals.WindowsState
  350. if eg.globals.WindowsState == "Fullscreen":
  351. osd_args = (
  352. u\'0;-60;0;0;0;700;255;0;0;0;3;2;1;34;Consolas\',
  353. (0, 255, 255),
  354. (0, 0, 0),
  355. 4,
  356. (0, 0),
  357. 1,
  358. 3.0,
  359. None
  360. )
  361. else:
  362. osd_args = (
  363. u\'0;-040;0;0;0;700;255;0;0;0;3;2;1;34;Consolas\',
  364. (0, 255, 255),
  365. (0, 0, 0),
  366. 4,
  367. (0, 0),
  368. 2,
  369. 3.0,
  370. None
  371. )
  372.  
  373. start = time.time()
  374.  
  375. # I trimmed down the percent math. iif you want to change an int to a
  376. # float you do not need to do 1.0 * int. this will work but the pythonic
  377. # way is to wrap that int with float()
  378. percent = (
  379. (
  380. float(elapsed.total_seconds()) /
  381. float(duration.total_seconds())
  382. ) * 100.0
  383. )
  384. # I removed the conversion of the percent form a float to an int because
  385. # i wanted the percent as a float for use further on down the line
  386.  
  387. bars = \'/\' * int(round(percent))
  388. remaining = \'.\' * (100 - len(bars))
  389.  
  390. # I created string templates for the OSD. i split the osd into 3 sections
  391. # I will explain as to why they are split into 3 sections further down
  392. # I added the percent that has elapsed to the bar line as a 2 decimal place
  393. # float
  394.  
  395. bar = BAR_TEMPLATE.format(
  396. bars=bars,
  397. remaining=remaining,
  398. percent=percent
  399. )
  400.  
  401. elapsed_total = ELAPSED_TOTAL_TEMPLATE.format(
  402. elapsed=_elapsed,
  403. duration=_duration
  404. )
  405.  
  406. # OK so this is an odd thing. wx is thee GUI interface we use to generate
  407. # all of the graphics, windows and controls in EG. because of how text
  408. # gets displayed when using a GUI the characters defined in a font are
  409. # not of equal size, so a "G" does not have the same width as an "!"
  410. # I saw that you were displaying the OSD n the center of the screen with
  411. # what looked like center justification. because of that font issue ths
  412. # is extremely difficult to do. Portions of the wx library allow us to call
  413. # a function called GetTextExtent this function rill return the width and
  414. # height in pixels of a string passed into it. we have to set the font we
  415. # want to use then call the function. in order to get the center
  416. # justification as close as we can and the space is the only thing we can
  417. # really do it with we also want to know the width of a space.
  418.  
  419. stop = time.time()
  420. ##print \'building the bar\', (stop - start) * 1000, \'milliseconds\'
  421.  
  422. start = time.time()
  423. frame = wx.Frame(None, -1)
  424. font = wx.FontFromNativeInfoString(osd_args[0])
  425. frame.SetFont(font)
  426. bar_len = frame.GetTextExtent(bar)[0]
  427. title_len = frame.GetTextExtent(title)[0]
  428. elapsed_total_len = frame.GetTextExtent(elapsed_total)[0]
  429. space_len = frame.GetTextExtent(\' \')[0]
  430.  
  431. # so here we do the checking to see which line is longer then the other to
  432. # adjust the one that is shorter
  433. if bar_len < title_len:
  434. # this is the number of spaces we are going to need. so we find out the
  435. # pixel difference divide that by the number of pixels a space is.
  436. # this is going to return the total number of spaces needed to make the
  437. # line the same length. Now remember center justification. so half of
  438. # those spaces would need to be on thee back end of the line. Those
  439. # we do not need to add to the line. so wee divide the total number of
  440. # spaces by 2 to get the number of spaces we need to add to the front
  441. # of the line
  442.  
  443. space_count = (
  444. int(round(float(title_len - bar_len) / float(space_len))) / 2
  445. )
  446. bar = \' \' * space_count + bar
  447.  
  448. elif title_len < bar_len:
  449. space_count = (
  450. int(round(float(bar_len - title_len) / float(space_len))) / 2
  451. )
  452. title = \' \' * space_count + title
  453.  
  454. bar_len = frame.GetTextExtent(bar)[0]
  455.  
  456. frame.Destroy()
  457.  
  458. if elapsed_total_len < bar_len:
  459. space_count = (
  460. int(round(
  461. float(bar_len - elapsed_total_len) / float(space_len))) / 2
  462. )
  463. elapsed_total = \' \' * space_count + elapsed_total
  464.  
  465. osd = OSD_TEMPLATE.format(
  466. title=title,
  467. bar=bar,
  468. elapsed_total=elapsed_total
  469. )
  470. # and here is the single call to ShowOSD. we prefiix that variable we made
  471. # earlier with a * which expands the variable into the parameters that
  472. # needs to be passed
  473. stop = time.time()
  474. print \'calculating bar position on the screen\', (stop - start) * 1000, \'milliseconds\'
  475.  
  476. eg.plugins.EventGhost.ShowOSD(osd, *osd_args)
  477.  
Tags: eventghost
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement