Help.. how OSD not working with Japanese fonts

Questions and comments specific to a particular plugin should go here.
Post Reply
molitar
Experienced User
Posts: 212
Joined: Fri Sep 11, 2009 6:44 am

Help.. how OSD not working with Japanese fonts

Post by molitar » Sun Jun 21, 2020 6:21 am

It took me a bit of time to figure out why Show OSD will not work with some videos. It appears it does not like foreign font types and throws up this error.
New OSD Style
imports and setup 0.0 milliseconds
GetTopLevelWindowList 0.0 milliseconds
_GetWindowThreadProcessId 82.9999446869 milliseconds
is fullscreen 0.0 milliseconds
GetWindowText 0.0 milliseconds
windows text evaluation 0.0 milliseconds
eg.plugins.MediaPlayerClassic.GetTimes 0.0 milliseconds
time evaluation 0.0 milliseconds
Fullscreen
building the bar 0.0 milliseconds
Traceback (most recent call last):
Python script "9", line 462, in <module>
elapsed_total=elapsed_total
UnicodeEncodeError: 'ascii' codec can't encode characters in position 51-60: ordinal not in range(128)
管理人さんのお this Japanese language is there an easy fix for the Japanese font not working with Show OSD?

jachin99
Experienced User
Posts: 646
Joined: Sat Feb 13, 2016 8:39 pm

Re: Help.. how OSD not working with Japanese fonts

Post by jachin99 » Sun Jun 21, 2020 10:01 pm

This is a wild guess but I would make sure the Japanese language pack is installed on your PC. You might also need a Japanese don't pack.

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Help.. how OSD not working with Japanese fonts

Post by kgschlosser » Mon Jun 22, 2020 6:26 am

yes it is an easy fix. but I am going to need to know how your are trying to show the OSD. are your using an action or calling it from a script?

if you are using an action I need to know what you have entered in the text box.
if it is from a script i am going to need to see the line in the script that makes the call to show the OSD
If you like the work I have been doing then feel free to Image

molitar
Experienced User
Posts: 212
Joined: Fri Sep 11, 2009 6:44 am

Re: Help.. how OSD not working with Japanese fonts

Post by molitar » Fri Sep 11, 2020 10:38 pm

kgschlosser wrote:
Mon Jun 22, 2020 6:26 am
yes it is an easy fix. but I am going to need to know how your are trying to show the OSD. are your using an action or calling it from a script?

if you are using an action I need to know what you have entered in the text box.
if it is from a script i am going to need to see the line in the script that makes the call to show the OSD
Well had a chance to get back to EventGhost. I am calling it by a script.

Code: Select all

# this try/except routine is done because the information that is generated
# in a Python script is persistent between runs. Whats this means is that
# anything that is created in a python script when the script gets run a
# second, third, fourth... the objects created the first time are available to
# every run thereafter. So if you have any objects created that are static and
# do not change between runs then there is no need to make them over again.
# To test for this we simply use one of those object names that are static.
# if the object exists it will pass right on by. if it oes not it will
# generate an error that we catch in the except portion of thee code block.
# And that is where we will then create all of the static objects


# adjustable set between 0 and 255
MAX_TRANSPARENT = 255

import time

start = time.time()
try:
    user32
except NameError:
    import wx
    import datetime
    import time
    import threading
    import ctypes
    from ctypes.wintypes import (
        BOOL,
        LONG,
        UINT,
        POINT,
        RECT,
        HWND,
        LPARAM,
        DWORD
    )  # NOQA

    from eg.WinApi import (
        GetWindowText,
        GetTopLevelWindowList,
        GetProcessName
    )  # NOQA

    from eg.WinApi.Dynamic import (
        SetWindowPos,
        SWP_FRAMECHANGED,
        SWP_NOACTIVATE,
        SWP_NOOWNERZORDER,
        SWP_SHOWWINDOW,
    )


    HWND_FLAGS = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED

    GWL_STYLE = -16
    GWL_EXSTYLE = -20
    WS_BORDER = 0x00800000
    WS_DLGFRAME = 0x00400000
    WS_THICKFRAME = 0x00040000
    WS_EX_WINDOWEDGE = 0x00000100
    WS_POPUP = 0x80000000
    WS_EX_TOPMOST = 0x00000008

    PID = DWORD
    user32 = ctypes.windll.User32

    # DWORD GetWindowThreadProcessId(
    #   HWND    hWnd,
    #   LPDWORD lpdwProcessId
    # );
    _GetWindowThreadProcessId = user32.GetWindowThreadProcessId
    _GetWindowThreadProcessId.restype = DWORD

    # LONG GetWindowLongW(
    #   HWND hWnd,
    #   int  nIndex
    # );

    _GetWindowLong = user32.GetWindowLongW
    _GetWindowLong.restype = LONG

    # HWND GetActiveWindow(
    #
    # );
    _GetActiveWindow = user32.GetActiveWindow
    _GetActiveWindow.restype = HWND

    BAR_TEMPLATE = '[{bars}{remaining}] - {percent:.2f}%'
    ELAPSED_TOTAL_TEMPLATE = 'Elapsed: {elapsed} / Total: {duration}'
    OSD_TEMPLATE = '{title}\n \n{bar}\n{elapsed_total}'
    osd_frame = eg.plugins.EventGhost.actions['ShowOSD'].osdFrame
    _old_show_osd = osd_frame.ShowOSD
    _old_on_timeout = osd_frame.OnTimeout

    eg.globals.fade_in_event = threading.Event()
    eg.globals.fade_out_event = threading.Event()


stop = time.time()

print 'imports and setup', (stop - start) * 1000, 'milliseconds'

start = time.time()
# OK so I removed the euse of the eg.WindowMatcher.
# it is a horribly slow thing to use and since we are only looking to see
# if a process is running or not we use GetTopLevelWindowList which returns
# the handles for the base window class of an application. then we ask windows
# to get us the process id (pid) for one of the handles in the returned list.
# Then we use that pid to get the process name. and we match that process name
# up with the one we are looking for.

handles = GetTopLevelWindowList(False)

stop = time.time()

print 'GetTopLevelWindowList', (stop - start) * 1000, 'milliseconds'
start = time.time()
# OK so I added some code to locate which instance of mpc to use if more then
# one is running.
# I elected to do some crafty coding with this. What happens is after the the
# window handles are found I then query the Windows API to get thee styles of
# the window. i check for specific markers like if the window has a border and
# if the window is set to be the topmost window as these are things that get
# turned on/off when an application goes into a fullscreen mode. at the same
# time I am also checking for a copy of mpc that is the active window. I do
# this to cover my bases, if there is more then a single active copy and none
# of them are set to full screen it is going to choose the one that is active
# (has focus). if there is a fullscreen copy running and a second. and the
# second is active the fullscreen is going to be the one used.

for handle in handles[:]:
    pid = PID()
    _GetWindowThreadProcessId(HWND(handle), ctypes.byref(pid))

    process_name = GetProcessName(pid.value)

    # we check the process name of the window. if it does not match then we
    # remove it form the list.
    if process_name != 'mpc-hc64.exe':
        handles.remove(handle)

stop = time.time()

print '_GetWindowThreadProcessId', (stop - start) * 1000, 'milliseconds'

# if there are no windows found then we want to stop the macro from running and
# exit the script

if not handles:
    handle = None
    eg.StopMacro()
    eg.Exit()


handle = None
# I removed the use of eg.globals.WindowsState as a mechanism for checking if
# the app is in fullscreen mode. Because this is one of the things we are
# looking for when we pick the window to use we no longer need to depend on
# an outside source to determine the window state. So you can remove that from
# your tree if you want.
is_fullscreen = False


start = time.time()
for hwnd in handles:
    # getting the windows styles and extended styles.
    style = _GetWindowLong(HWND(hwnd), GWL_STYLE)
    style_ex = _GetWindowLong(HWND(hwnd), GWL_EXSTYLE)

    # checking the styles for specific markers.
    if (
        not style & WS_BORDER and
        not style & WS_DLGFRAME and
        not style & WS_THICKFRAME and
        not style_ex & WS_EX_WINDOWEDGE and
        style & WS_POPUP and
        style_ex & WS_EX_TOPMOST
    ):
        # if there are 2 copies of mpc running and both are fullscreen then
        # we are going to use the one that is active
        if is_fullscreen is False:
            handle = hwnd
            is_fullscreen = True
        elif _GetActiveWindow() == hwnd:
            handle = hwnd
            is_fullscreen = True

    # if there is no full screen one found already and this window is active
    # then we seet it into place
    elif handle is None and _GetActiveWindow() == hwnd:
        handle = hwnd
        is_fullscreen = False

stop = time.time()

print 'is fullscreen', (stop - start) * 1000, 'milliseconds'


# fallback if something does not work properly in the code.
if handle is None:
    handle = handles[0]

start = time.time()
window_text = GetWindowText(handle)
stop = time.time()
print 'GetWindowText', (stop - start) * 1000, 'milliseconds'

# I removed the use of re and did a simple trial and error using a for loop
# with an else statement.
# If i split a string on a value and that value is not n the string it is
# going to return a list with the original string at index 0. So the list
# only las a length of 1. if it did have the value in it the list would have a
# length greater then 1. and we use that to break the loop. This will cause
# the else to not get run.

start = time.time()
for item in (".mkv", ".mp4", ".avi", ".ogm"):
    window_text = window_text.split(item)
    if len(window_text) > 1:
        break
    window_text = window_text[0]
else:
    window_text = window_text.split('.')

stop = time.time()

print 'windows text evaluation', (stop - start) * 1000, 'milliseconds'


title = window_text[0]


start = time.time()
_elapsed, _remaining, _duration = eg.plugins.MediaPlayerClassic.GetTimes()
# print "elaps, rem, total =",elaps, rem, total

# I removed all of that math involved in trying to get the seconds in
# favor of using time.strptime and datetime.timedelta
# time.strptime will take a string formatted time representation and turn it
# into a python object for us. we simply have to provide details as to how the
# string is formatted. you can get more information on the identifiers here
# http://strftime.org/
# once we have that object which only does the simple
# conversion to hours minutes seconds we need to create another object that
# does the match for us and will return the total seconds

stop = time.time()
print 'eg.plugins.MediaPlayerClassic.GetTimes', (stop - start) * 1000, 'milliseconds'

start = time.time()
while _elapsed.count(':') < 2:
    _elapsed = '00:' + _elapsed
while _remaining.count(':') < 2:
    _remaining = '00:' + _remaining
while _duration.count(':') < 2:
    _duration = '00:' + _duration

elapsed = time.strptime(_elapsed, '%H:%M:%S')
elapsed = datetime.timedelta(
    hours=elapsed.tm_hour,
    minutes=elapsed.tm_min,
    seconds=elapsed.tm_sec
)

remaining = time.strptime(_remaining, '%H:%M:%S')
remaining = datetime.timedelta(
    hours=remaining.tm_hour,
    minutes=remaining.tm_min,
    seconds=remaining.tm_sec
)

duration = time.strptime(_duration, '%H:%M:%S')
duration = datetime.timedelta(
    hours=duration.tm_hour,
    minutes=duration.tm_min,
    seconds=duration.tm_sec
)

stop = time.time()
print 'time evaluation', (stop - start) * 1000, 'milliseconds'

# heere we do a test to see if elapsed has any seconds to it. if iit does
# that means the video is playing and to generate the osd
if elapsed.total_seconds():
    def fade_in():
        beg = time.time()
        for i in range(MAX_TRANSPARENT):
            if eg.globals.fade_in_event.isSet():
                break
            osd_frame.SetTransparent(i)
            eg.globals.fade_in_event.wait(0.01)

        osd_frame.ShowOSD = _old_show_osd
        end = time.time()

        print 'fade in', (end - beg) * 1000, 'milliseconds'


    def fade_out():
        beg = time.time()

        for i in range(MAX_TRANSPARENT, 255, -1):
            if eg.globals.fade_out_event.isSet():
                break
            osd_frame.SetTransparent(i)
            eg.globals.fade_out_event.wait(0.01)

        _old_on_timeout()
        osd_frame.OnTimeout = _old_on_timeout
        end = time.time()

        print 'fade out', (end - beg) * 1000, 'milliseconds'

    def show_osd(*args, **kwargs):
        args = list(args)
        args[7] += MAX_TRANSPARENT * 0.01

        eg.globals.fade_out_event.set()
        eg.globals.fade_in_event.clear()

        osd_frame.SetTransparent(0)
        _old_show_osd(*args, **kwargs)

        fade_in()

    def on_timeout():
        eg.globals.fade_in_event.set()
        eg.globals.fade_out_event.clear()
        fade_out()


    osd_frame.ShowOSD = show_osd
    osd_frame.OnTimeout = on_timeout

    # instead of having to calls to ShowOSD we can set the parameters we want
    # to pass to ShowOSD into a variable you name the variable the same for
    # Fullscreen and not Fullscreen and set the parameters for each variation
    # then when we call ShowOSD the proper set of parameters will be passed
    
    #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)
    #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)
    
    print eg.globals.WindowsState
    if eg.globals.WindowsState == "Fullscreen":
        osd_args = (
            u'0;-60;0;0;0;700;255;0;0;0;3;2;1;34;Consolas',
            (0, 255, 255),
            (0, 0, 0),
            4,
            (0, 0),
            1,
            3.0,
            None
        )
    else:
        osd_args = (
            u'0;-030;0;0;0;700;255;0;0;0;3;2;1;34;Consolas',
            (0, 255, 255),
            (0, 0, 0),
            4,
            (0, 0),
            2,
            3.0,
            None
        )
        
    start = time.time()

    # I trimmed down the percent math. iif you want to change an int to a
    # float you do not need to do 1.0 * int. this will work but the pythonic
    # way is to wrap that int with float()
    percent = (
        (
            float(elapsed.total_seconds()) /
            float(duration.total_seconds())
        ) * 100.0
    )
    # I removed the conversion of the percent form a float to an int because
    # i wanted the percent as a float for use further on down the line

    bars = '/' * int(round(percent))
    remaining = '.' * (100 - len(bars))

    # I created string templates for the OSD. i split the osd into 3 sections
    # I will explain as to why they are split into 3 sections further down
    # I added the percent that has elapsed to the bar line as a 2 decimal place
    # float

    bar = BAR_TEMPLATE.format(
        bars=bars,
        remaining=remaining,
        percent=percent
    )

    elapsed_total = ELAPSED_TOTAL_TEMPLATE.format(
        elapsed=_elapsed,
        duration=_duration
    )

    # OK so this is an odd thing. wx is thee GUI interface we use to generate
    # all of the graphics, windows and controls in EG. because of how text
    # gets displayed when using a GUI the characters defined in a font are
    # not of equal size, so a "G" does not have the same width as an "!"
    # I saw that you were displaying the OSD n the center of the screen with
    # what looked like center justification. because of that font issue ths
    # is extremely difficult to do. Portions of the wx library allow us to call
    # a function called GetTextExtent this function rill return the width and
    # height in pixels of a string passed into it. we have to set the font we
    # want to use then call the function. in order to get the center
    # justification as close as we can and the space is the only thing we can
    # really do it with we also want to know the width of a space.

    stop = time.time()
    print 'building the bar', (stop - start) * 1000, 'milliseconds'

    start = time.time()
    frame = wx.Frame(None, -1)
    font = wx.FontFromNativeInfoString(osd_args[0])
    frame.SetFont(font)
    bar_len = frame.GetTextExtent(bar)[0]
    title_len = frame.GetTextExtent(title)[0]
    elapsed_total_len = frame.GetTextExtent(elapsed_total)[0]
    space_len = frame.GetTextExtent(' ')[0]

    # so here we do the checking to see which line is longer then the other to
    # adjust the one that is shorter
    if bar_len < title_len:
        # this is the number of spaces we are going to need. so we find out the
        # pixel difference divide that by the number of pixels a space is.
        # this is going to return the total number of spaces needed to make the
        # line the same length. Now remember center justification. so half of
        # those spaces would need to be on thee back end of the line. Those
        # we do not need to add to the line. so wee divide the total number of
        # spaces by 2 to get the number of spaces we need to add to the front
        # of the line

        space_count = (
            int(round(float(title_len - bar_len) / float(space_len))) / 2
        )
        bar = ' ' * space_count + bar

    elif title_len < bar_len:
        space_count = (
            int(round(float(bar_len - title_len) / float(space_len))) / 2
        )
        title = ' ' * space_count + title

    bar_len = frame.GetTextExtent(bar)[0]

    frame.Destroy()

    if elapsed_total_len < bar_len:
        space_count = (
            int(round(
                float(bar_len - elapsed_total_len) / float(space_len))) / 2
        )
        elapsed_total = ' ' * space_count + elapsed_total

    osd = OSD_TEMPLATE.format(
        title=title,
        bar=bar,
        elapsed_total=elapsed_total
    )
    # and here is the single call to ShowOSD. we prefiix that variable we made
    # earlier with a * which expands the variable into the parameters that
    # needs to be passed
    stop = time.time()
    print 'calculating bar position on the screen', (stop - start) * 1000, 'milliseconds'

    eg.plugins.EventGhost.ShowOSD(osd, *osd_args)

User avatar
kgschlosser
Site Admin
Posts: 5498
Joined: Fri Jun 05, 2015 5:43 am
Location: Rocky Mountains, Colorado USA

Re: Help.. how OSD not working with Japanese fonts

Post by kgschlosser » Sat Sep 12, 2020 2:46 am

unicode problems in Python 2.7 are a pain to deal with. Give the code below a shot and see if it works. I might have to decode to latin1 and then encode to utf-8 or just decode as utf-8 or it could be encode then decode. I can't remember off hand. I will get it working for you tho

Code: Select all


# this try/except routine is done because the information that is generated
# in a Python script is persistent between runs. Whats this means is that
# anything that is created in a python script when the script gets run a
# second, third, fourth... the objects created the first time are available to
# every run thereafter. So if you have any objects created that are static and
# do not change between runs then there is no need to make them over again.
# To test for this we simply use one of those object names that are static.
# if the object exists it will pass right on by. if it oes not it will
# generate an error that we catch in the except portion of thee code block.
# And that is where we will then create all of the static objects


# adjustable set between 0 and 255
MAX_TRANSPARENT = 255

import time

start = time.time()
try:
    user32
except NameError:
    import wx
    import datetime
    import time
    import threading
    import ctypes
    from ctypes.wintypes import (
        BOOL,
        LONG,
        UINT,
        POINT,
        RECT,
        HWND,
        LPARAM,
        DWORD
    )  # NOQA

    from eg.WinApi import (
        GetWindowText,
        GetTopLevelWindowList,
        GetProcessName
    )  # NOQA

    from eg.WinApi.Dynamic import (
        SetWindowPos,
        SWP_FRAMECHANGED,
        SWP_NOACTIVATE,
        SWP_NOOWNERZORDER,
        SWP_SHOWWINDOW,
    )


    HWND_FLAGS = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED

    GWL_STYLE = -16
    GWL_EXSTYLE = -20
    WS_BORDER = 0x00800000
    WS_DLGFRAME = 0x00400000
    WS_THICKFRAME = 0x00040000
    WS_EX_WINDOWEDGE = 0x00000100
    WS_POPUP = 0x80000000
    WS_EX_TOPMOST = 0x00000008

    PID = DWORD
    user32 = ctypes.windll.User32

    # DWORD GetWindowThreadProcessId(
    #   HWND    hWnd,
    #   LPDWORD lpdwProcessId
    # );
    _GetWindowThreadProcessId = user32.GetWindowThreadProcessId
    _GetWindowThreadProcessId.restype = DWORD

    # LONG GetWindowLongW(
    #   HWND hWnd,
    #   int  nIndex
    # );

    _GetWindowLong = user32.GetWindowLongW
    _GetWindowLong.restype = LONG

    # HWND GetActiveWindow(
    #
    # );
    _GetActiveWindow = user32.GetActiveWindow
    _GetActiveWindow.restype = HWND

    BAR_TEMPLATE = '[{bars}{remaining}] - {percent:.2f}%'
    ELAPSED_TOTAL_TEMPLATE = 'Elapsed: {elapsed} / Total: {duration}'
    OSD_TEMPLATE = '{title}\n \n{bar}\n{elapsed_total}'
    osd_frame = eg.plugins.EventGhost.actions['ShowOSD'].osdFrame
    _old_show_osd = osd_frame.ShowOSD
    _old_on_timeout = osd_frame.OnTimeout

    eg.globals.fade_in_event = threading.Event()
    eg.globals.fade_out_event = threading.Event()


stop = time.time()

print 'imports and setup', (stop - start) * 1000, 'milliseconds'

start = time.time()
# OK so I removed the euse of the eg.WindowMatcher.
# it is a horribly slow thing to use and since we are only looking to see
# if a process is running or not we use GetTopLevelWindowList which returns
# the handles for the base window class of an application. then we ask windows
# to get us the process id (pid) for one of the handles in the returned list.
# Then we use that pid to get the process name. and we match that process name
# up with the one we are looking for.

handles = GetTopLevelWindowList(False)

stop = time.time()

print 'GetTopLevelWindowList', (stop - start) * 1000, 'milliseconds'
start = time.time()
# OK so I added some code to locate which instance of mpc to use if more then
# one is running.
# I elected to do some crafty coding with this. What happens is after the the
# window handles are found I then query the Windows API to get thee styles of
# the window. i check for specific markers like if the window has a border and
# if the window is set to be the topmost window as these are things that get
# turned on/off when an application goes into a fullscreen mode. at the same
# time I am also checking for a copy of mpc that is the active window. I do
# this to cover my bases, if there is more then a single active copy and none
# of them are set to full screen it is going to choose the one that is active
# (has focus). if there is a fullscreen copy running and a second. and the
# second is active the fullscreen is going to be the one used.

for handle in handles[:]:
    pid = PID()
    _GetWindowThreadProcessId(HWND(handle), ctypes.byref(pid))

    process_name = GetProcessName(pid.value)

    # we check the process name of the window. if it does not match then we
    # remove it form the list.
    if process_name != 'mpc-hc64.exe':
        handles.remove(handle)

stop = time.time()

print '_GetWindowThreadProcessId', (stop - start) * 1000, 'milliseconds'

# if there are no windows found then we want to stop the macro from running and
# exit the script

if not handles:
    handle = None
    eg.StopMacro()
    eg.Exit()


handle = None
# I removed the use of eg.globals.WindowsState as a mechanism for checking if
# the app is in fullscreen mode. Because this is one of the things we are
# looking for when we pick the window to use we no longer need to depend on
# an outside source to determine the window state. So you can remove that from
# your tree if you want.
is_fullscreen = False


start = time.time()
for hwnd in handles:
    # getting the windows styles and extended styles.
    style = _GetWindowLong(HWND(hwnd), GWL_STYLE)
    style_ex = _GetWindowLong(HWND(hwnd), GWL_EXSTYLE)

    # checking the styles for specific markers.
    if (
        not style & WS_BORDER and
        not style & WS_DLGFRAME and
        not style & WS_THICKFRAME and
        not style_ex & WS_EX_WINDOWEDGE and
        style & WS_POPUP and
        style_ex & WS_EX_TOPMOST
    ):
        # if there are 2 copies of mpc running and both are fullscreen then
        # we are going to use the one that is active
        if is_fullscreen is False:
            handle = hwnd
            is_fullscreen = True
        elif _GetActiveWindow() == hwnd:
            handle = hwnd
            is_fullscreen = True

    # if there is no full screen one found already and this window is active
    # then we seet it into place
    elif handle is None and _GetActiveWindow() == hwnd:
        handle = hwnd
        is_fullscreen = False

stop = time.time()

print 'is fullscreen', (stop - start) * 1000, 'milliseconds'


# fallback if something does not work properly in the code.
if handle is None:
    handle = handles[0]

start = time.time()
window_text = GetWindowText(handle)
stop = time.time()
print 'GetWindowText', (stop - start) * 1000, 'milliseconds'

# I removed the use of re and did a simple trial and error using a for loop
# with an else statement.
# If i split a string on a value and that value is not n the string it is
# going to return a list with the original string at index 0. So the list
# only las a length of 1. if it did have the value in it the list would have a
# length greater then 1. and we use that to break the loop. This will cause
# the else to not get run.

start = time.time()
for item in (".mkv", ".mp4", ".avi", ".ogm"):
    window_text = window_text.split(item)
    if len(window_text) > 1:
        break
    window_text = window_text[0]
else:
    window_text = window_text.split('.')

stop = time.time()

print 'windows text evaluation', (stop - start) * 1000, 'milliseconds'


title = window_text[0]


start = time.time()
_elapsed, _remaining, _duration = eg.plugins.MediaPlayerClassic.GetTimes()
# print "elaps, rem, total =",elaps, rem, total

# I removed all of that math involved in trying to get the seconds in
# favor of using time.strptime and datetime.timedelta
# time.strptime will take a string formatted time representation and turn it
# into a python object for us. we simply have to provide details as to how the
# string is formatted. you can get more information on the identifiers here
# http://strftime.org/
# once we have that object which only does the simple
# conversion to hours minutes seconds we need to create another object that
# does the match for us and will return the total seconds

stop = time.time()
print 'eg.plugins.MediaPlayerClassic.GetTimes', (stop - start) * 1000, 'milliseconds'

start = time.time()
while _elapsed.count(':') < 2:
    _elapsed = '00:' + _elapsed
while _remaining.count(':') < 2:
    _remaining = '00:' + _remaining
while _duration.count(':') < 2:
    _duration = '00:' + _duration

elapsed = time.strptime(_elapsed, '%H:%M:%S')
elapsed = datetime.timedelta(
    hours=elapsed.tm_hour,
    minutes=elapsed.tm_min,
    seconds=elapsed.tm_sec
)

remaining = time.strptime(_remaining, '%H:%M:%S')
remaining = datetime.timedelta(
    hours=remaining.tm_hour,
    minutes=remaining.tm_min,
    seconds=remaining.tm_sec
)

duration = time.strptime(_duration, '%H:%M:%S')
duration = datetime.timedelta(
    hours=duration.tm_hour,
    minutes=duration.tm_min,
    seconds=duration.tm_sec
)

stop = time.time()
print 'time evaluation', (stop - start) * 1000, 'milliseconds'

# heere we do a test to see if elapsed has any seconds to it. if iit does
# that means the video is playing and to generate the osd
if elapsed.total_seconds():
    def fade_in():
        beg = time.time()
        for i in range(MAX_TRANSPARENT):
            if eg.globals.fade_in_event.isSet():
                break
            osd_frame.SetTransparent(i)
            eg.globals.fade_in_event.wait(0.01)

        osd_frame.ShowOSD = _old_show_osd
        end = time.time()

        print 'fade in', (end - beg) * 1000, 'milliseconds'


    def fade_out():
        beg = time.time()

        for i in range(MAX_TRANSPARENT, 255, -1):
            if eg.globals.fade_out_event.isSet():
                break
            osd_frame.SetTransparent(i)
            eg.globals.fade_out_event.wait(0.01)

        _old_on_timeout()
        osd_frame.OnTimeout = _old_on_timeout
        end = time.time()

        print 'fade out', (end - beg) * 1000, 'milliseconds'

    def show_osd(*args, **kwargs):
        args = list(args)
        args[7] += MAX_TRANSPARENT * 0.01

        eg.globals.fade_out_event.set()
        eg.globals.fade_in_event.clear()

        osd_frame.SetTransparent(0)
        _old_show_osd(*args, **kwargs)

        fade_in()

    def on_timeout():
        eg.globals.fade_in_event.set()
        eg.globals.fade_out_event.clear()
        fade_out()


    osd_frame.ShowOSD = show_osd
    osd_frame.OnTimeout = on_timeout

    # instead of having to calls to ShowOSD we can set the parameters we want
    # to pass to ShowOSD into a variable you name the variable the same for
    # Fullscreen and not Fullscreen and set the parameters for each variation
    # then when we call ShowOSD the proper set of parameters will be passed

    #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)
    #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)

    print eg.globals.WindowsState
    if eg.globals.WindowsState == "Fullscreen":
        osd_args = (
            u'0;-60;0;0;0;700;255;0;0;0;3;2;1;34;Consolas',
            (0, 255, 255),
            (0, 0, 0),
            4,
            (0, 0),
            1,
            3.0,
            None
        )
    else:
        osd_args = (
            u'0;-030;0;0;0;700;255;0;0;0;3;2;1;34;Consolas',
            (0, 255, 255),
            (0, 0, 0),
            4,
            (0, 0),
            2,
            3.0,
            None
        )

    start = time.time()

    # I trimmed down the percent math. iif you want to change an int to a
    # float you do not need to do 1.0 * int. this will work but the pythonic
    # way is to wrap that int with float()
    percent = (
        (
            float(elapsed.total_seconds()) /
            float(duration.total_seconds())
        ) * 100.0
    )
    # I removed the conversion of the percent form a float to an int because
    # i wanted the percent as a float for use further on down the line

    bars = '/' * int(round(percent))
    remaining = '.' * (100 - len(bars))

    # I created string templates for the OSD. i split the osd into 3 sections
    # I will explain as to why they are split into 3 sections further down
    # I added the percent that has elapsed to the bar line as a 2 decimal place
    # float

    bar = BAR_TEMPLATE.format(
        bars=bars,
        remaining=remaining,
        percent=percent
    )

    elapsed_total = ELAPSED_TOTAL_TEMPLATE.format(
        elapsed=_elapsed,
        duration=_duration
    )

    # OK so this is an odd thing. wx is thee GUI interface we use to generate
    # all of the graphics, windows and controls in EG. because of how text
    # gets displayed when using a GUI the characters defined in a font are
    # not of equal size, so a "G" does not have the same width as an "!"
    # I saw that you were displaying the OSD n the center of the screen with
    # what looked like center justification. because of that font issue ths
    # is extremely difficult to do. Portions of the wx library allow us to call
    # a function called GetTextExtent this function rill return the width and
    # height in pixels of a string passed into it. we have to set the font we
    # want to use then call the function. in order to get the center
    # justification as close as we can and the space is the only thing we can
    # really do it with we also want to know the width of a space.

    stop = time.time()
    print 'building the bar', (stop - start) * 1000, 'milliseconds'

    start = time.time()
    frame = wx.Frame(None, -1)
    font = wx.FontFromNativeInfoString(osd_args[0])
    frame.SetFont(font)
    bar_len = frame.GetTextExtent(bar)[0]
    title_len = frame.GetTextExtent(title)[0]
    elapsed_total_len = frame.GetTextExtent(elapsed_total)[0]
    space_len = frame.GetTextExtent(' ')[0]

    # so here we do the checking to see which line is longer then the other to
    # adjust the one that is shorter
    if bar_len < title_len:
        # this is the number of spaces we are going to need. so we find out the
        # pixel difference divide that by the number of pixels a space is.
        # this is going to return the total number of spaces needed to make the
        # line the same length. Now remember center justification. so half of
        # those spaces would need to be on thee back end of the line. Those
        # we do not need to add to the line. so wee divide the total number of
        # spaces by 2 to get the number of spaces we need to add to the front
        # of the line

        space_count = (
            int(round(float(title_len - bar_len) / float(space_len))) / 2
        )
        bar = ' ' * space_count + bar

    elif title_len < bar_len:
        space_count = (
            int(round(float(bar_len - title_len) / float(space_len))) / 2
        )
        title = ' ' * space_count + title

    bar_len = frame.GetTextExtent(bar)[0]

    frame.Destroy()

    if elapsed_total_len < bar_len:
        space_count = (
            int(round(
                float(bar_len - elapsed_total_len) / float(space_len))) / 2
        )
        elapsed_total = ' ' * space_count + elapsed_total

    osd = OSD_TEMPLATE.format(
        title=title.decode('utf-8'),
        bar=bar,
        elapsed_total=elapsed_total
    )
    # and here is the single call to ShowOSD. we prefiix that variable we made
    # earlier with a * which expands the variable into the parameters that
    # needs to be passed
    stop = time.time()
    print 'calculating bar position on the screen', (stop - start) * 1000, 'milliseconds'

    eg.plugins.EventGhost.ShowOSD(osd, *osd_args)

If you like the work I have been doing then feel free to Image

Post Reply