疯人院里的快乐时光

疯,不为常规所度测……

关于Kodi字幕插件的开发

最近把家里的HDPC终于改成Debian了,起初一直在Windows 10下,但经过长时间的使用,装着E5200芯的老机器终于拉不动了,启动都要卡半天。思索了半天,干脆换到了Debian下。没去试现在的安卓X86版本和凤凰系统,是因为不想过于折腾了,虽说Debian并不是个好的娱乐平台,但好在安装Kodi倒是很方便对这个系统也比较熟悉,而我也仅仅用它就可以了。

安装的是Debian 9.4版本, Kodi是17.6的。设置什么的轻车熟路,电影、电视、直播啥的都基本没问题,但找遍了网上现有的中文字幕插件,就没一个可以用的,有的说是给15的版本可以用,但我没试而且也不想换版本。没办法了,只有自己改吧。

在这里真要吐槽一下Kodi的官方资料,英文的不说,而且是积极的简单,什么函数基本上就是一句话解释,连示例都没有一个,不过还好,综合了很多现成的源码,基本上了解了它字幕插件的思路和一些函数方法。代码是基于网络现有的插件基础上改的,字幕来源于字幕库。

首先是搜索函数,一番查验这个到是简单,原先的代码找不到内容是因为网站页面div的class改了,所以把bs的查找规则调整就ok了。

def Search( item ):
    subtitles_list = []

    log( __name__ ,"Search for [%s] by name" % (os.path.basename( item['file_original_path'] ),))
    if item['mansearch']:
        url = ZIMUKU_API % (item['mansearchstr'])
    else:
        url = ZIMUKU_API % (item['title'])
    try:
        socket = urllib.urlopen(url)
        data = socket.read()
        socket.close()
        soup = BeautifulSoup(data,'html.parser')
    except:
        return
    results = soup.find_all("div", class_="item prel clearfix")
    for it in results:
        moviename = it.find("div", class_="title").a.text.encode('utf-8')
        iurl = it.find("div", class_="title").a.get('href').encode('utf-8')
        movieurl = '%s%s' % (ZIMUKU_BASE, iurl)
        try:
            socket = urllib.urlopen(movieurl)
            data = socket.read()
            socket.close()
            soup = BeautifulSoup(data,'html.parser').find("table", class_="table")
            soup = soup.find("tbody")
        except:
            return
        subs = soup.find_all("tr")
        for sub in subs:
            name = sub.a.text.encode('utf-8')
            if name.split('.')[-1] not in ['zip','Zip','ZIP']: continue
            flag = sub.img.get('src').split('/')[-1].split('.')[0].encode('utf-8')
            lang = FLAG_DICT.get(flag,'unkonw')
            link = '%s%s' % (ZIMUKU_BASE, sub.a.get('href').encode('utf-8'))

            if lang == '英':
                subtitles_list.append({"language_name":"English", "filename":name, "link":link, "language_flag":'en', "rating":"0", "lang":lang})
            else:
                subtitles_list.append({"language_name":"Chinese", "filename":name, "link":link, "language_flag":'zh', "rating":"0", "lang":lang})

而下载函数就麻烦了一点,看原来代码是获取下载地址后直接下载,而实际上我在网站下载时发现网站使用了301重定向,并且在访问下载地址时,网站做了防爬虫处理,需要在头里带上Referer,否则系统是不会给你正确的定向地址的,经过改动的代码如下:

def Download(url,lang):
    try: shutil.rmtree(__temp__)
    except: pass
    try: os.makedirs(__temp__)
    except: pass

    exts = [".srt", ".sub", ".smi", ".ssa", ".ass" ]
    try:
        socket = urllib.urlopen( url )
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        url = soup.find("li", class_="li dlsub").a.get('href').encode('utf-8')
        socket = urllib.urlopen(url)

        socket = urllib.urlopen(url)
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        div = soup.find('div',class_='down clearfix')
        li = div.find('li')
        headers['Referer'] = url

        req = urllib2.Request(li.a.get('href'),headers=headers)
        resp = urllib2.urlopen(req)
        socket = urllib.urlopen(resp.geturl())
        data = socket.read()
        socket.close()
    except:
        return []
    if len(data) < 1024: return []
    tempfile = os.path.join(__temp__, "subtitles.zip")
    xbmc.log(tempfile)
    with open(tempfile, "wb") as subFile: subFile.write(data)
    subFile.close()
    xbmc.sleep(500)
    lists = unZip(tempfile)
    lists = [i for i in lists if os.path.splitext(i)[1] in exts]

    if len(lists) == 1:
        return lists[0]
    else:
        index = [i.split('/')[-1] for i in lists]
        sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', index)
        if sel == -1: sel = 0
        return lists[sel]

经过调整,大的问题没有了,不过些小的地方,原代码里貌似是只能在Windows下用的,因为好像它是用Winrar来解压的,而我在Debian下使用,所以只能考虑Zip文件了,至于能不能用rar包还有单独的srt等文件,以后折腾吧。

def getFileList(path):
    fileslist = []
    for d in os.listdir(path):
        if os.path.isdir(path+d):
            fileslist.extend(getFileList(path+d+'/'))
        if os.path.isfile(path+d):
            fileslist.append(path+d)
    return fileslist

def unZip(filepath):
    zip_file = zipfile.ZipFile(filepath,'r')
    for names in zip_file.namelist():
        if type(names) == str and names[-1] != '/':
            utf8name = names.decode('gbk')
            data = zip_file.read(names)
            fo = open(os.path.join(__temp__, utf8name), "w")
            fo.write(data)
            fo.close()
        else:
            zip_file.extract(names,__temp__)
    return getFileList(__temp__+'/')

总结一下啊,用惯了Python3后用2真的不习惯,并且在Kodi里测试也是非常的不方便,改动一下需要重新进入才行,经过测试在Linux和Windows下都没问题,版本从17到最新的18,至于更低的版本则没测试,接下来要把各种字幕扩展名的文件下载功能补全,等到某一天有心情折腾了再说吧。附地址:https://pan.baidu.com/s/1GxAod4Xdll-3pvM_OOru8A

更新:由于上次改的有太多的局限性,所以继续抽时间改了改,现在这个版本继续支持Linux和Windows,并且文件格式由单纯的zip扩展到rar的压缩,还包括了各种未压缩的字幕格式,由于网上并没有发现7z的字幕压缩包,所以就没有考虑这个格式了。但现在由于格式的增多,就带来了一些问题,为了这个插件的正常使用,在Windows下必须要安装WinRAR并且目录还得是C:\Program Files\WinRAR,在Linux下需要安装unrar,否则的话会下载失败,其他没有要求,注意这点即可。

贴上代码:

def getFileList(path):
    fileslist = []
    for d in os.listdir(path):
        if os.path.isdir(path+d):
            fileslist.extend(getFileList(path+d+'/'))
        if os.path.isfile(path+d):
            fileslist.append(path+d)
    return fileslist

def extractCompress(file):
    path  = __temp__ + '/subtitles/'
    if os.path.isdir(path): shutil.rmtree(path)
    if not os.path.isdir(path): os.mkdir(path)

    if file.lower().endswith('zip'):
        zipFile = zipfile.ZipFile(file,'r')
        for names in zipFile.namelist():
            if type(names) == str and names[-1] != '/':
                utf8name = names.decode('gbk')
                data = zipFile.read(names)
                with open(path+utf8name, 'wb') as f: f.write(data)
            else:
                zipFile.extract(names,path)
        return getFileList(path)

    if file.lower().endswith('rar'):
        if platform.system() == 'Windows':
            rarPath = 'C:\Program Files\WinRAR'
            sysPath = os.getenv('Path')
            if 'winrar' not in sysPath.lower(): os.environ["Path"] = sysPath+';'+rarPath
            command = "winrar x -ibck %s %s" % (file, path)
        if platform.system() == 'Linux':
            command = 'unrar x %s %s' % (file, path)
        res = os.system(command)
        if res == 0: return getFileList(path)

def Search( item ):
    subtitles_list = []

    log(__name__ ,"Search for [%s] by name" % os.path.basename(item['file_original_path']))
    if item['mansearch']:
        url = ZIMUKU_API % (item['mansearchstr'])
    else:
        url = ZIMUKU_API % (item['title'])
    try:
        socket = urllib.urlopen(url)
        data = socket.read()
        socket.close()
        soup = BeautifulSoup(data,'html.parser')
    except:
        return
    results = soup.find_all("div", class_="item prel clearfix")
    for it in results:
        moviename = it.find("div", class_="title").a.text.encode('utf-8')
        iurl = it.find("div", class_="title").a.get('href').encode('utf-8')
        movieurl = '%s%s' % (ZIMUKU_BASE, iurl)
        try:
            socket = urllib.urlopen(movieurl)
            data = socket.read()
            socket.close()
            soup = BeautifulSoup(data,'html.parser').find("table", class_="table")
            soup = soup.find("tbody")
        except:
            return
        subs = soup.find_all("tr")
        for sub in subs:
            name = sub.a.text.encode('utf-8')
            flag = sub.img.get('src').split('/')[-1].split('.')[0].encode('utf-8')
           .get(flag,'unkonw')
            link = '%s%s' % (ZIMUKU_BASE, sub.a.get('href').encode('utf-8'))

            if lang == '英':
                subtitles_list.append({"language_name":"English", "filename":name, "link":link, "language_flag":'en', "rating":"0", "lang":lang})
            else:
                subtitles_list.append({"language_name":"Chinese", "filename":name, "link":link, "language_flag":'zh', "rating":"0", "lang":lang})

    if subtitles_list:
        for it in subtitles_list:
            listitem = xbmcgui.ListItem(label=it["language_name"],
                                  label2=it["filename"],
                                  iconImage=it["rating"],
                                  thumbnailImage=it["language_flag"]
                                  )

            listitem.setProperty( "sync", "false" )
            listitem.setProperty( "hearing_imp", "false" )

            url = "plugin://%s/?action=download&link=%s&lang=%s" % (__scriptid__,
                                                                        it["link"],
                                                                        it["lang"]
                                                                        )
            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=url,listitem=listitem,isFolder=False)

def Download(url,lang):
    try: shutil.rmtree(__temp__)
    except: pass
    try: os.makedirs(__temp__)
    except: pass

    exts = [".srt", ".sub", ".smi", ".ssa", ".ass" ]
    try:
        socket = urllib.urlopen( url )
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        url = soup.find("li", class_="li dlsub").a.get('href').encode('utf-8')
        socket = urllib.urlopen(url)

        socket = urllib.urlopen(url)
        data = socket.read()
        soup = BeautifulSoup(data,'html.parser')
        div = soup.find('div',class_='down clearfix')
        li = div.find('li')
        headers['Referer'] = url

        req = urllib2.Request(li.a.get('href'),headers=headers)
        resp = urllib2.urlopen(req)
        fileName = resp.headers['Content-Disposition'].replace('"','').split('=')[1]

        socket = urllib.urlopen(resp.geturl())
        data = socket.read()
        socket.close()
    except:
        return []
    if len(data) < 1024: return []
    tempfile = os.path.join(__temp__, "subtitles.%s" % fileName.split('.')[-1])
    xbmc.log(tempfile)
    with open(tempfile, "wb") as subFile: subFile.write(data)
    xbmc.sleep(100)
    if fileName.split('.')[-1].lower() in ('zip','rar'):
        lists = extractCompress(tempfile)
    else:
        lists = [tempfile]

    lists = [i for i in lists if os.path.splitext(i)[1] in exts]

    if len(lists) == 1:
        return lists[0]
    else:
        index = [i.split('/')[-1] for i in lists]
        sel = xbmcgui.Dialog().select('请选择压缩包中的字幕', index)
        if sel == -1: sel = 0
        return lists[sel]

贴上下载地址:点击下载

点赞
  1. kodier说道:

    您好,请问下您的debian是怎么安装的kodi17.6 版本的,我试了所有的软件源,自带的都是17.1,更高的版本都只有源码了,如果您是源码安装的话,能指点一下是怎么安装的吗,我的系统是debian9

    1. JeFF.Hou说道:

      我忘记什么版本了,我现在没用Debian做播放器了,你碰到什么问题了吗?

发表评论

邮箱地址不会被公开。 必填项已用*标注