kodi中python3调用you-get

最近打算把you-get放到kodi里面当一个视频插件,结果发现踩了好多坑。本来以为有现成函数可以直接调用,去搜了搜没找到,看了知乎这个https://www.zhihu.com/question/54939203问题,我表示服气的,高票教育一个小白去看文档。。。(然而根本没有开发文档可以看(小程序可以理解),文档里全是命令行用法,写程序根本没法用。费这时间要么你就直接告诉人家正确用法要么你就别回答,害得我找了那么久,不如直接说让我去直接看代码好了)底下还贴出几个代码,用os和sys.argv的,跟需求差得有点远,于是自己看代码。

上面纯属吐嘈。

目前kodi的版本为18,master分支仅支持python2,需要自行编译feature_python3分支。

将you-get封装成为kodi模块,或者可以直接安装我封装好的:)

https://github.com/feilongfl/script.module.you_get

安装后即可。

这里有一个坑,直接封装会出现这个错误

ERROR: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
                                             - NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
                                            Error Type: <class 'AttributeError'>
                                            Error Contents: 'xbmcout' object has no attribute 'buffer'
                                            Traceback (most recent call last):
                                              File "/home/feilong/.kodi/addons/plugin.youget/main.py", line 12, in <module>
                                                from resources.lib import plugin
                                              File "/home/feilong/.kodi/addons/plugin.youget/resources/lib/plugin.py", line 9, in <module>
                                                from you_get import common as youget
                                              File "/home/feilong/.kodi/addons/script.module.you_get/lib/you_get/common.py", line 22, in <module>
                                                sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
                                            AttributeError: 'xbmcout' object has no attribute 'buffer'

因为在kodi中使用xbmcout没有buffer这个元素,实际用不到,注释掉就可以了

if sys.stdout.isatty():
    default_encoding = sys.stdout.encoding.lower()
else:
    default_encoding = locale.getpreferredencoding().lower()

这里也是同理,保留最后一行。

在kodi插件中添加

        <import addon="script.module.you_get" version="0.4.1193"/>

准备工作结束,于是终于到了调用you-get的时候。

总之先上代码吧,懒得看后面的可以直接抄走:)不过这部分代码仅仅是测试使用,所以只能播放一个视频,没有其他功能,只是展示下调用方法。

# -*- coding: utf-8 -*-

import routing
import logging
import xbmcaddon
import sys
from you_get import common as youget
from xbmcgui import ListItem
from xbmcplugin import addDirectoryItem, endOfDirectory
import xbmc


ADDON = xbmcaddon.Addon()
plugin = routing.Plugin()


@plugin.route('/')
def index():
    addDirectoryItem(plugin.handle, plugin.url_for(
        show_category, "one"), ListItem("Category One"), False)
    addDirectoryItem(plugin.handle, plugin.url_for(
        show_category, "two"), ListItem("Category Two"), True)
    endOfDirectory(plugin.handle)


@plugin.route('/category/<category_id>')
def show_category(category_id):
    runCmd([1,2])
    addDirectoryItem(
        plugin.handle, "", ListItem("Hello category %s!" % category_id))
    endOfDirectory(plugin.handle)

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    playUrl(urls[0])
    return

def playUrl(video_url):
    playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
    playlist.clear()
    li = ListItem(path=video_url)
    li.setInfo( type="video", infoLabels={ "Path" : video_url } )
    playlist.add(url=video_url, listitem=li)
    xbmc.Player().play(playlist)

def test_main(**kwargs):
    youget.script_main(youget.any_download, youget.any_download_playlist, **kwargs)

def runCmd(command):
    extra = {}
    URLs = ['https://www.youtube.com/watch?v=AnwQAWmGgek']
    youget.set_socks_proxy("feilong-server.lan:10080")
    youget.download_urls = download_urls
    youget.download_main(
        youget.any_download, youget.any_download_playlist,
        URLs, False,
        output_dir='/tmp/', merge=True,
        info_only=False, json_output=False,
        **extra
    )

def run():
    plugin.run()

emmm,上面就是插件部分代码了。

主要调用部分是runCmd,因为最开始看了知乎的sys.argv,后来发现输出都在stdout里面,不想重定向于是看代码。

导入youget这个没什么好说的,看这名字,看看知乎,看看这体积,看看main函数就决定是common了:)

from you_get import common as youget

如果是在桌面环境下播放视频,确实是可以通过类似下面这种用法来运行。

    sys.argv=['you-get', 'https://www.youtube.com/watch?v=AnwQAWmGgek']
    youget.main()

但是在kodi中,需要拦截视频url并将其传递给kodi,由kodi解码播放。然而我看了看,貌似最后都在调用download_urls这个函数来下载视频,于是重载这个函数

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    playUrl(urls[0])
    return
youget.download_urls = download_urls

然后调用这个

youget.download_main(
        youget.any_download, youget.any_download_playlist,
        # URLs, args.playlist,
        URLs, False,
        # output_dir=args.output_dir, merge=not args.no_merge,
        output_dir='/tmp/', merge=True,
        info_only=False, json_output=False,
        # password=args.password,
        **extra
    )

就可以播放了

顺便之前没有传递http的header,所以一些视频不能播放

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    url = urls[0]
    for key, value in headers.items():
        print (key,' => ',value)
        url = "%s|%s='%s'" % (url,key,value)

    playUrl(url)
    return

添加进去就好了。