来自 Python 的 Sonos Unicode 播放列表

Unicode Playlists for Sonos from Python

我正在努力将一小部分音乐从我的 iTunes 库导出到外部驱动器,以便与 Sonos 扬声器一起使用(通过 Sonos 上的媒体库)。一切都很顺利,直到我在曲目、专辑和艺术家姓名中遇到一些 unicode 文本。

我要从 Mac 上的 iTunes 移动到 Linux (Ubuntu) 上的文件夹结构,文件路径都包含原始的 Unicode 名称,这些名称显示和在艺术家/专辑视图中从 Sonos 正常播放。唯一的问题是播放列表,这是我通过一些 Python3 代码生成的。

Sonos 似乎不支持 .m3u / .m3u8 播放列表中的 UTF-8 编码。 Sonos 将字符 ÷ 解释为 Ã,经过一些谷歌搜索后,我发现它明显混淆了 UTF-8 和 UTF-16(÷ UTF-8 中的 0xC3 0xB7,而 Ã 是 UTF-16 中的 U+00C3 和· 在 UTF-16 中是 U+00B7)。我已经尝试了许多不同的编码方式,但就是无法让它识别名称中包含非标准(非 ASCII?)字符的曲目。

然后我尝试了 .wpl 播放列表,并认为我已经解决了它。路径中带有 ÷ 和 • 等字符的曲目现在可以完美运行,只需在播放列表文件本身中使用它们的 unicode / UTF-8 格式的字符。

但是,就在我开始整理和完成代码时,我发现其他一些字符没有得到正确处理:ö、å、á 和其他几个字符。我试过将它们用作它们的原始 unicode 字符,但也用作它们编码的 XML 标识符,例如́ 使用此格式对有效或无效没有影响 - ÷ (÷) 和 • (•) 都可以,而 ö (ö ), å (å) 和 á (á) 不是。

我以前从未真正使用过 unicode/UTF-8,但在阅读了各种指南和操作方法后,我觉得我已经接近了,但可能只是遗漏了一些简单的东西。事实上,一些 unicode 字符现在可以工作,而另一些则不能,这让我觉得这一定是显而易见的!我猜不同之处在于重音修饰了前一个字符,而不是本身是一个字符,但尝试删除前一个字母但没有用!

在 Python 本身,我并没有做任何特别聪明的事情。我使用以下方法从 iTunes 的 XML 文件中读取数据:

    with open(settings['itunes_path'], 'rb') as itunes_handle:
        itunes_library = plistlib.load(itunes_handle)

对于导出,我尝试了数十种不同的选项,但通常如下所示(有时使用 encoding='utf-8' 和各种其他选项):

with open(dest_path, 'w') as playlist_file:
    playlist_file.write(generated_playlist)

其中 generated_playlist 是从 itunes_library 中提取和过滤数据的结果,在任何 iTunes XML 数据上具有 运行 urllib.parse.unquote()

任何关于在哪里查看的想法或提示将不胜感激!我希望对于更了解 Unicode 的人来说,答案真的很明显!谢谢!

此处提供的当前代码版本:https://github.com/dwalker-uk/iTunesToSonos

感谢@lenz 提出的上述建议,我现在拥有完全适用于 Sonos 的 unicode 播放列表。

几个关键点可以为别人节省很多时间:

  • 似乎只有 .wpl 播放列表有效。 Unicode 不适用于 Sonos 上的 .m3u 或 .m3u8 播放列表。
  • Sonos 需要将任何 unicode 文本规范化为 NFC 格式 - 我以前从未听说过,但本质上意味着任何重音字符都必须由单个字符表示,而不是作为具有单独字符的普通字符口音。
  • .pls 播放列表是 XML 格式,需要以 XML 格式编码的 unicode 字符,即 é 在 .pls 文件中表示为 é.
  • .pls 文件还需要转义形式的 XML 保留字符 (& < > ' "),即 &&amp;.

在Python3中,将iTunesXML格式的路径转换为适合Sonos上的.pls播放列表的格式,需要以下关键步骤:

left = len(itunes_library['Music Folder'])
path_relative = 'Media/' + itunes_library['Tracks'][track_id]['Location'][left:]
path_unquoted = urllib.parse.unquote(path_relative)
path_norm = unicodedata.normalize('NFC', path_unquoted)
path = path_norm.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')

playlist_wpl += '<media src="%s"/>\n' % path

with open(pl_path, 'wb') as pl_file:
    pl_file.write(playlist_wpl.encode('ascii', 'xmlcharrefreplace'))

从 iTunes 导出以在 Sonos(或其他任何东西)中作为 .pls 使用的完整工作演示可在此处获得:https://github.com/dwalker-uk/iTunesToSonos

希望对某人有所帮助!