IP controlled relay board

If you have a question or need help, this is the place to be.
Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Wed May 20, 2020 8:29 am

Here's the latest -

Code: Select all

import requests

data = '''\
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
            <ObjectID>Q:0</ObjectID>
            <BrowseFlag>BrowseDirectChildren</BrowseFlag>
            <Filter>dc:title,dc:creator</Filter>
             <StartingIndex>{starting_index}</StartingIndex>
            <RequestedCount>10</RequestedCount>
            <SortCriteria></SortCriteria>
        </u:Browse>
    </s:Body>
</s:Envelope>
'''

starting_index = eg.event.payload.split('=')[-1]
data = data.format(starting_index=starting_index )

headers = {
    'Content-Type': 'text/html; charset=UTF-8',
    'SOAPACTION': 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse',
    'Content-Length': len(data)
}

response = requests.post('http://192.168.0.32:1400/MediaServer/ContentDirectory/Control', data=data, headers=headers)

from xml.etree import ElementTree

data = response.content

# this function strips namespace information
def strip_namespaces(in_data):
    lines = []
    line = ''

    for char in list(in_data):
        if char == '>':
            line += char
            lines += [line]
            line = ''
            continue
        elif char == '<' and line:
            lines += [line]
            line = ''

        line += char

    if line:
        lines += [line]

    for i, line in enumerate(lines):
        if '<' not in line:
            continue

        while 'xmlns=' in line:
            beg, end = line.split('xmlns=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

        while 'xmlns:' in line:
            beg, end = line.split('xmlns:', 1)
            xmlns, end = end.split('=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

            while xmlns + ':encodingStyle=' in line:
                beg, end = line.split(xmlns + ':encodingStyle=', 1)
                end = end.split('"', 2)[-1].strip()
                line = beg + end

            lines[i] = line

            for j, lne in enumerate(lines[i:]):
                if '<' not in lne:
                    continue
                lne = lne.replace('<' + xmlns + ':', '<')
                lne = lne.replace('</' + xmlns + ':', '</')

                lines[i + j] = lne

    out_data = ''.join(lines)
    return ''.join(line for line in out_data.split('\n'))

# strip the namespace data here
data = strip_namespaces(data)

# create an xml object from the stripped data
xml = ElementTree.fromstring(data)

# locate the elements that we are looking for
body = xml.find('Body')
browse_response = body.find('BrowseResponse')
result = browse_response.find('Result')

# data is stored in the text area of the result field
data = result.text

# strip the namespaces from the result data
data = strip_namespaces(data)

# turn the result data into an xml object
xml = ElementTree.fromstring(data.encode('utf-8'))

track = 1
for item in xml:
    message = 'artist' + str(track) + ':' + item.find('creator').text + ':'
    eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)

    message = 'title' + str(track) + ':' + item.find('title').text + ':'
    eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)

    if track == 1:
        message = 'artist:' + item.find('creator').text + ':'
        message = message.replace('!', '%21')
        message = message.replace('&', '%26')
        message = message.replace(';', '%3B')
        eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)
        
        message = 'album:' + item.find('album').text + ':'
        message = message.replace('!', '%21')
        message = message.replace('&', '%26')
        message = message.replace(';', '%3B')
        eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)
        
#    print 'res:', item.find('res').text
#    print 'albumArtURI:', item.find('albumArtURI').text
#    print 'class:', item.find('class').text

    track = track + 1
        
while track < 11:
    message = 'artist' + str(track) + ':  :'
    eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)

    message = 'title' + str(track) + ':  :'
    eg.plugins.BroadcastListener.Broadcast(message, u'', 33339)
    
    track = track + 1

Cheers,
Peter

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

Re: IP controlled relay board

Post by kgschlosser » Thu May 21, 2020 4:56 am

give this whirly bird a twirl.

Code: Select all

import requests

data = '''\
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
            <ObjectID>Q:0</ObjectID>
            <BrowseFlag>BrowseDirectChildren</BrowseFlag>
            <Filter>dc:title,dc:creator</Filter>
             <StartingIndex>{starting_index}</StartingIndex>
            <RequestedCount>10</RequestedCount>
            <SortCriteria></SortCriteria>
        </u:Browse>
    </s:Body>
</s:Envelope>
'''

starting_index = eg.event.payload.split('=')[-1]
data = data.format(starting_index=starting_index)

headers = {
    'Content-Type': 'text/html; charset=UTF-8',
    'SOAPACTION': 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse',
    'Content-Length': len(data)
}

response = requests.post(
    'http://192.168.0.32:1400/MediaServer/ContentDirectory/Control',
    data=data, 
    headers=headers
)

from xml.etree import ElementTree

data = response.content


# this function strips namespace information
def strip_namespaces(in_data):
    lines = []
    line = ''

    for char in list(in_data):
        if char == '>':
            line += char
            lines += [line]
            line = ''
            continue
        elif char == '<' and line:
            lines += [line]
            line = ''

        line += char

    if line:
        lines += [line]

    for i, line in enumerate(lines):
        if '<' not in line:
            continue

        while 'xmlns=' in line:
            beg, end = line.split('xmlns=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

        while 'xmlns:' in line:
            beg, end = line.split('xmlns:', 1)
            xmlns, end = end.split('=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

            while xmlns + ':encodingStyle=' in line:
                beg, end = line.split(xmlns + ':encodingStyle=', 1)
                end = end.split('"', 2)[-1].strip()
                line = beg + end

            lines[i] = line

            for j, lne in enumerate(lines[i:]):
                if '<' not in lne:
                    continue
                lne = lne.replace('<' + xmlns + ':', '<')
                lne = lne.replace('</' + xmlns + ':', '</')

                lines[i + j] = lne

    out_data = ''.join(lines)
    return ''.join(line for line in out_data.split('\n'))


# strip the namespace data here
data = strip_namespaces(data)

# create an xml object from the stripped data
xml = ElementTree.fromstring(data)

# locate the elements that we are looking for
body = xml.find('Body')
browse_response = body.find('BrowseResponse')
result = browse_response.find('Result')

# data is stored in the text area of the result field
data = result.text

# strip the namespaces from the result data
data = strip_namespaces(data)

# So i added the xml decleration line which has an encoding attribute.
# I am hoping this is going to solve the issue you are having. 
# if it does not this is bacause the encoding that is being used
# by your computer running EG differs from the encoding that is being used by
# your media server. we may have to do some additional encoding and decoding 
# to give it a kick in the ass to work, but lets give this a shot first.
data = '<?xml version="1.0" encoding="UTF-8" ?>' + data
# turn the result data into an xml object
xml = ElementTree.fromstring(data)


# OK so here I subclassed str to build a custom formatter that 
# will remove any special characters if needed.
class SpecialFormat(str):

    def format(self, *args, **kwargs):
        if 'replace' in kwargs:
            args = '**??**'.join(str(itm) for itm in args)
            for pattern, value in (
                    ('!', '%21'),
                    ('&', '%26'),
                    (';', '%3B'),
            ):
                args = args.replace(pattern, value)
            args = args.split('**??**')

        return str.format(self, *args)

# because you were doing quite a bit of adding strings together
# and also because you had these 3 packate you are sending it
# is more efficient code to declare the packet a single time 
# and then plug in the information we need. the {0} and {1}
# mean argument 1 and argument 2 for the method format()
artist = SpecialFormat('artist{0}:{1}:')
title = SpecialFormat('title{0}:{1}:')
album = SpecialFormat('album{0}:{1}:')

# just a code reducing function. I set 
# the payload to None because you are not 
# sending any payload data.
def send(msg):
    eg.plugins.BroadcastListener.Broadcast(msg, None, 33339)


# reduction of code using a different iteration 
# technique to get the track number.
# I also used that new send function along with using format() 
# to reduce the amount of code needed here.
for track, item in enumerate(xml, start=1):
    send(artist.format(track, item.find('creator').text))
    send(title.format(track, item.find('title').text))

    if not track:
        send(artist.format('', item.find('creator').text, replace=True))
        send(album.format('', item.find('album').text, replace=True))
        # print 'res:', item.find('res').text
        # print 'albumArtURI:', item.find('albumArtURI').text
        # print 'class:', item.find('class').text

for track in range(track, 11):
    send(artist.format(track, '  '))
    send(title.format(track, '  '))

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

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Fri May 22, 2020 7:43 am

A couple of problems.

1. It's no longer sending artist and album, and instead its sending two artist10 and title10 with the second ones blank -

udp.artist1:k.d. lang:
udp.title1:Season of Hollow Soul:
udp.artist2:k.d. lang:
udp.title2:Constant Craving:
udp.artist3:Kate Bush:
udp.title3:Wuthering Heights:
udp.artist4:Kate Bush:
udp.title4:Feel It:
udp.artist5:Kylie Minogue:
udp.title5:Butterfly:
udp.artist6:Kylie Minogue:
udp.title6:Light Years:
udp.artist7:Kylie Minogue:
udp.title7:The One:
udp.artist8:Leona Lewis:
udp.title8:Run:
udp.artist9:Lighthouse Family:
udp.title9:Free/One:
udp.artist10:Lighthouse Family:
udp.title10:Whatever Gets You Through the Day:
udp.artist10: :
udp.title10: :

2. Accented characters are still tripping it up -

Traceback (most recent call last):
Python script "63", line 117, in <module>
xml = ElementTree.fromstring(data)
File "xml\etree\ElementTree.pyc", line 963, in XML
File "xml\etree\ElementTree.pyc", line 1245, in feed
UnicodeEncodeError: 'ascii' codec can't encode character u'\xeb' in position 479: ordinal not in range(128)

Cheers,
Peter

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Fri May 22, 2020 8:42 am

When there are less than 10 items in the queue the repeat is always on the last one. Here it's artist5 and title5 -

udp.artist1:Hunters & Collectors:
udp.title1:True Tears of Joy:
udp.artist2:Hunters & Collectors:
udp.title2:Where Do You Go?:
udp.artist3:Hunters & Collectors:
udp.title3:Back in the Hole:
udp.artist4:Hunters & Collectors:
udp.title4:Holy Grail:
udp.artist5:Hunters & Collectors:
udp.title5:Throw Your Arms Around Me:
udp.artist5: :
udp.title5: :
udp.artist6: :
udp.title6: :
udp.artist7: :
udp.title7: :
udp.artist8: :
udp.title8: :
udp.artist9: :
udp.title9: :
udp.artist10: :
udp.title10: :

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Wed May 27, 2020 12:35 pm

I made a couple of minor changes to this section -

Code: Select all

for track, item in enumerate(xml, start=1):
    send(artist.format(track, item.find('creator').text))
    send(title.format(track, item.find('title').text))

    if track ==1:
        send(artist.format('', item.find('creator').text, replace=True))
        send(album.format('', item.find('album').text, replace=True))
        # print 'res:', item.find('res').text
        # print 'albumArtURI:', item.find('albumArtURI').text
        # print 'class:', item.find('class').text

for track in range(track+1, 11):
    send(artist.format(track, '  '))
    send(title.format(track, '  '))
and it fixed problem 1.

The accented chars are still a problem.

Cheers,
Peter

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

Re: IP controlled relay board

Post by kgschlosser » Wed May 27, 2020 9:45 pm

let me see the error you are getting now after the changes have been made. I am wondering if the problem may have moved to a new location.
If you like the work I have been doing then feel free to Image

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Thu May 28, 2020 1:58 pm

Here's the latest code -

Code: Select all

import requests

data = '''\
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
            <ObjectID>Q:0</ObjectID>
            <BrowseFlag>BrowseDirectChildren</BrowseFlag>
            <Filter>dc:title,dc:creator</Filter>
             <StartingIndex>{starting_index}</StartingIndex>
            <RequestedCount>10</RequestedCount>
            <SortCriteria></SortCriteria>
        </u:Browse>
    </s:Body>
</s:Envelope>
'''

starting_index = eg.event.payload.split('=')[-1]
data = data.format(starting_index=starting_index)

headers = {
    'Content-Type': 'text/html; charset=UTF-8',
    'SOAPACTION': 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse',
    'Content-Length': len(data)
}

response = requests.post(
    'http://192.168.0.32:1400/MediaServer/ContentDirectory/Control',
    data=data, 
    headers=headers
)

from xml.etree import ElementTree

data = response.content


# this function strips namespace information
def strip_namespaces(in_data):
    lines = []
    line = ''

    for char in list(in_data):
        if char == '>':
            line += char
            lines += [line]
            line = ''
            continue
        elif char == '<' and line:
            lines += [line]
            line = ''

        line += char

    if line:
        lines += [line]

    for i, line in enumerate(lines):
        if '<' not in line:
            continue

        while 'xmlns=' in line:
            beg, end = line.split('xmlns=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

        while 'xmlns:' in line:
            beg, end = line.split('xmlns:', 1)
            xmlns, end = end.split('=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

            while xmlns + ':encodingStyle=' in line:
                beg, end = line.split(xmlns + ':encodingStyle=', 1)
                end = end.split('"', 2)[-1].strip()
                line = beg + end

            lines[i] = line

            for j, lne in enumerate(lines[i:]):
                if '<' not in lne:
                    continue
                lne = lne.replace('<' + xmlns + ':', '<')
                lne = lne.replace('</' + xmlns + ':', '</')

                lines[i + j] = lne

    out_data = ''.join(lines)
    return ''.join(line for line in out_data.split('\n'))


# strip the namespace data here
data = strip_namespaces(data)

# create an xml object from the stripped data
xml = ElementTree.fromstring(data)

# locate the elements that we are looking for
body = xml.find('Body')
browse_response = body.find('BrowseResponse')
result = browse_response.find('Result')

# data is stored in the text area of the result field
data = result.text

# strip the namespaces from the result data
data = strip_namespaces(data)

# So i added the xml decleration line which has an encoding attribute.
# I am hoping this is going to solve the issue you are having. 
# if it does not this is bacause the encoding that is being used
# by your computer running EG differs from the encoding that is being used by
# your media server. we may have to do some additional encoding and decoding 
# to give it a kick in the ass to work, but lets give this a shot first.
data = '<?xml version="1.0" encoding="UTF-8" ?>' + data
# turn the result data into an xml object
xml = ElementTree.fromstring(data)


# OK so here I subclassed str to build a custom formatter that 
# will remove any special characters if needed.
class SpecialFormat(str):

    def format(self, *args, **kwargs):
        if 'replace' in kwargs:
            args = '**??**'.join(str(itm) for itm in args)
            for pattern, value in (
                    ('!', '%21'),
                    ('&', '%26'),
                    (';', '%3B'),
            ):
                args = args.replace(pattern, value)
            args = args.split('**??**')

        return str.format(self, *args)

# because you were doing quite a bit of adding strings together
# and also because you had these 3 packate you are sending it
# is more efficient code to declare the packet a single time 
# and then plug in the information we need. the {0} and {1}
# mean argument 1 and argument 2 for the method format()
artist = SpecialFormat('artist{0}:{1}:')
title = SpecialFormat('title{0}:{1}:')
album = SpecialFormat('album{0}:{1}:')

# just a code reducing function. I set 
# the payload to None because you are not 
# sending any payload data.
def send(msg):
    eg.plugins.BroadcastListener.Broadcast(msg, None, 33339)


# reduction of code using a different iteration 
# technique to get the track number.
# I also used that new send function along with using format() 
# to reduce the amount of code needed here.
for track, item in enumerate(xml, start=1):
    send(artist.format(track, item.find('creator').text))
    send(title.format(track, item.find('title').text))

    if track ==1:
        send(artist.format('', item.find('creator').text, replace=True))
        send(album.format('', item.find('album').text, replace=True))
        # print 'res:', item.find('res').text
        # print 'albumArtURI:', item.find('albumArtURI').text
        # print 'class:', item.find('class').text

for track in range(track+1, 11):
    send(artist.format(track, '  '))
    send(title.format(track, '  '))
and here's the error message -

Traceback (most recent call last):
Python script "65", line 117, in <module>
xml = ElementTree.fromstring(data)
File "xml\etree\ElementTree.pyc", line 963, in XML
File "xml\etree\ElementTree.pyc", line 1245, in feed
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1775: ordinal not in range(128)

Cheers,
Peter

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

Re: IP controlled relay board

Post by kgschlosser » Fri May 29, 2020 4:02 am

give this one a shot. for the life of me I can't remember if it needs to be encoded or decoded. But we will soon know.

Code: Select all

import requests

data = '''\
        <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <s:Body>
                <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
                    <ObjectID>Q:0</ObjectID>
                    <BrowseFlag>BrowseDirectChildren</BrowseFlag>
                    <Filter>dc:title,dc:creator</Filter>
                     <StartingIndex>{starting_index}</StartingIndex>
                    <RequestedCount>10</RequestedCount>
                    <SortCriteria></SortCriteria>
                </u:Browse>
            </s:Body>
        </s:Envelope>
        '''

starting_index = eg.event.payload.split('=')[-1]
data = data.format(starting_index=starting_index)

headers = {
    'Content-Type': 'text/html; charset=UTF-8',
    'SOAPACTION': 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse',
    'Content-Length': len(data)
}

response = requests.post(
    'http://192.168.0.32:1400/MediaServer/ContentDirectory/Control',
    data=data,
    headers=headers
)

from xml.etree import ElementTree

data = response.content


# this function strips namespace information
def strip_namespaces(in_data):
    lines = []
    line = ''

    for char in list(in_data):
        if char == '>':
            line += char
            lines += [line]
            line = ''
            continue
        elif char == '<' and line:
            lines += [line]
            line = ''

        line += char

    if line:
        lines += [line]

    for i, line in enumerate(lines):
        if '<' not in line:
            continue

        while 'xmlns=' in line:
            beg, end = line.split('xmlns=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

        while 'xmlns:' in line:
            beg, end = line.split('xmlns:', 1)
            xmlns, end = end.split('=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

            while xmlns + ':encodingStyle=' in line:
                beg, end = line.split(xmlns + ':encodingStyle=', 1)
                end = end.split('"', 2)[-1].strip()
                line = beg + end

            lines[i] = line

            for j, lne in enumerate(lines[i:]):
                if '<' not in lne:
                    continue
                lne = lne.replace('<' + xmlns + ':', '<')
                lne = lne.replace('</' + xmlns + ':', '</')

                lines[i + j] = lne

    out_data = ''.join(lines)
    return ''.join(line for line in out_data.split('\n'))


# strip the namespace data here
data = strip_namespaces(data)

# create an xml object from the stripped data
xml = ElementTree.fromstring(data)

# locate the elements that we are looking for
body = xml.find('Body')
browse_response = body.find('BrowseResponse')
result = browse_response.find('Result')

# data is stored in the text area of the result field
data = result.text

# strip the namespaces from the result data
data = strip_namespaces(data)

# So i added the xml decleration line which has an encoding attribute.
# I am hoping this is going to solve the issue you are having.
# if it does not this is bacause the encoding that is being used
# by your computer running EG differs from the encoding that is being used by
# your media server. we may have to do some additional encoding and decoding
# to give it a kick in the ass to work, but lets give this a shot first.
data = '<?xml version="1.0" encoding="UTF-8" ?>' + data
# turn the result data into an xml object
xml = ElementTree.fromstring(data.decode('utf-8'))


# OK so here I subclassed str to build a custom formatter that
# will remove any special characters if needed.
class SpecialFormat(str):

    def format(self, *args, **kwargs):
        if 'replace' in kwargs:
            args = '**??**'.join(str(itm) for itm in args)
            for pattern, value in (
                    ('!', '%21'),
                    ('&', '%26'),
                    (';', '%3B'),
            ):
                args = args.replace(pattern, value)
            args = args.split('**??**')

        return str.format(self, *args)


# because you were doing quite a bit of adding strings together
# and also because you had these 3 packate you are sending it
# is more efficient code to declare the packet a single time
# and then plug in the information we need. the {0} and {1}
# mean argument 1 and argument 2 for the method format()
artist = SpecialFormat('artist{0}:{1}:')
title = SpecialFormat('title{0}:{1}:')
album = SpecialFormat('album{0}:{1}:')


# just a code reducing function. I set
# the payload to None because you are not
# sending any payload data.
def send(msg):
    eg.plugins.BroadcastListener.Broadcast(msg, None, 33339)


# reduction of code using a different iteration
# technique to get the track number.
# I also used that new send function along with using format()
# to reduce the amount of code needed here.
for track, item in enumerate(xml, start=1):
    send(artist.format(track, item.find('creator').text))
    send(title.format(track, item.find('title').text))

    if track == 1:
        send(artist.format('', item.find('creator').text, replace=True))
        send(album.format('', item.find('album').text, replace=True))
        # print 'res:', item.find('res').text
        # print 'albumArtURI:', item.find('albumArtURI').text
        # print 'class:', item.find('class').text

for track in range(track + 1, 11):
    send(artist.format(track, '  '))
    send(title.format(track, '  '))
If you like the work I have been doing then feel free to Image

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Fri May 29, 2020 5:35 am

OK here's the error message from that one -

Traceback (most recent call last):
Python script "66", line 117, in <module>
xml = ElementTree.fromstring(data.decode('utf-8'))
File "encodings\utf_8.pyc", line 16, in decode
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1223: ordinal not in range(128)

Cheers,
Peter

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

Re: IP controlled relay board

Post by kgschlosser » Sat May 30, 2020 12:44 am

next!!!
LOL

Code: Select all

import requests

data = '''\
        <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <s:Body>
                <u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
                    <ObjectID>Q:0</ObjectID>
                    <BrowseFlag>BrowseDirectChildren</BrowseFlag>
                    <Filter>dc:title,dc:creator</Filter>
                     <StartingIndex>{starting_index}</StartingIndex>
                    <RequestedCount>10</RequestedCount>
                    <SortCriteria></SortCriteria>
                </u:Browse>
            </s:Body>
        </s:Envelope>
        '''

starting_index = eg.event.payload.split('=')[-1]
data = data.format(starting_index=starting_index)

headers = {
    'Content-Type': 'text/html; charset=UTF-8',
    'SOAPACTION': 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse',
    'Content-Length': len(data)
}

response = requests.post(
    'http://192.168.0.32:1400/MediaServer/ContentDirectory/Control',
    data=data,
    headers=headers
)

from xml.etree import ElementTree

data = response.content


# this function strips namespace information
def strip_namespaces(in_data):
    lines = []
    line = ''

    for char in list(in_data):
        if char == '>':
            line += char
            lines += [line]
            line = ''
            continue
        elif char == '<' and line:
            lines += [line]
            line = ''

        line += char

    if line:
        lines += [line]

    for i, line in enumerate(lines):
        if '<' not in line:
            continue

        while 'xmlns=' in line:
            beg, end = line.split('xmlns=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

        while 'xmlns:' in line:
            beg, end = line.split('xmlns:', 1)
            xmlns, end = end.split('=', 1)
            end = end.split('"', 2)[-1].strip()
            line = beg + end

            while xmlns + ':encodingStyle=' in line:
                beg, end = line.split(xmlns + ':encodingStyle=', 1)
                end = end.split('"', 2)[-1].strip()
                line = beg + end

            lines[i] = line

            for j, lne in enumerate(lines[i:]):
                if '<' not in lne:
                    continue
                lne = lne.replace('<' + xmlns + ':', '<')
                lne = lne.replace('</' + xmlns + ':', '</')

                lines[i + j] = lne

    out_data = ''.join(lines)
    return ''.join(line for line in out_data.split('\n'))


# strip the namespace data here
data = strip_namespaces(data)

# create an xml object from the stripped data
xml = ElementTree.fromstring(data)

# locate the elements that we are looking for
body = xml.find('Body')
browse_response = body.find('BrowseResponse')
result = browse_response.find('Result')

# data is stored in the text area of the result field
data = result.text

# strip the namespaces from the result data
data = strip_namespaces(data)

# So i added the xml decleration line which has an encoding attribute.
# I am hoping this is going to solve the issue you are having.
# if it does not this is bacause the encoding that is being used
# by your computer running EG differs from the encoding that is being used by
# your media server. we may have to do some additional encoding and decoding
# to give it a kick in the ass to work, but lets give this a shot first.
data = '<?xml version="1.0" encoding="UTF-8" ?>' + data
# turn the result data into an xml object
xml = ElementTree.fromstring(data.encode('utf-8'))


# OK so here I subclassed str to build a custom formatter that
# will remove any special characters if needed.
class SpecialFormat(str):

    def format(self, *args, **kwargs):
        if 'replace' in kwargs:
            args = '**??**'.join(str(itm) for itm in args)
            for pattern, value in (
                    ('!', '%21'),
                    ('&', '%26'),
                    (';', '%3B'),
            ):
                args = args.replace(pattern, value)
            args = args.split('**??**')

        return str.format(self, *args)


# because you were doing quite a bit of adding strings together
# and also because you had these 3 packate you are sending it
# is more efficient code to declare the packet a single time
# and then plug in the information we need. the {0} and {1}
# mean argument 1 and argument 2 for the method format()
artist = SpecialFormat('artist{0}:{1}:')
title = SpecialFormat('title{0}:{1}:')
album = SpecialFormat('album{0}:{1}:')


# just a code reducing function. I set
# the payload to None because you are not
# sending any payload data.
def send(msg):
    eg.plugins.BroadcastListener.Broadcast(msg, None, 33339)


# reduction of code using a different iteration
# technique to get the track number.
# I also used that new send function along with using format()
# to reduce the amount of code needed here.
for track, item in enumerate(xml, start=1):
    send(artist.format(track, item.find('creator').text))
    send(title.format(track, item.find('title').text))

    if track == 1:
        send(artist.format('', item.find('creator').text, replace=True))
        send(album.format('', item.find('album').text, replace=True))
        # print 'res:', item.find('res').text
        # print 'albumArtURI:', item.find('albumArtURI').text
        # print 'class:', item.find('class').text

for track in range(track + 1, 11):
    send(artist.format(track, '  '))
    send(title.format(track, '  '))
If you like the work I have been doing then feel free to Image

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Sat May 30, 2020 5:54 am

Different error -

Traceback (most recent call last):
Python script "67", line 160, in <module>
send(artist.format(track, item.find('creator').text))
Python script "67", line 135, in format
return str.format(self, *args)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xeb' in position 4: ordinal not in range(128)

Cheers,
Peter

Peter M
Posts: 46
Joined: Tue Jun 18, 2019 5:13 am

Re: IP controlled relay board

Post by Peter M » Fri Jun 05, 2020 7:38 am

I decide that this wasn't worth spending any more time on as it applies to such a small subset of my music.

So I've ended up editing out all the accented characters in Artist and Album names.

Thanks again for all your help.

Cheers,
Peter

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

Re: IP controlled relay board

Post by kgschlosser » Sat Jun 06, 2020 4:38 am

OK cool. unicode problems are a HUGE annoyance with python 2. a lot of the annoyances simmer down in python 3 but some are still there.
If you like the work I have been doing then feel free to Image

Post Reply