py2 984856b358da cached
176 files
1.3 MB
569.8k tokens
833 symbols
1 requests
Download .txt
Showing preview only (1,673K chars total). Download the full file or copy to clipboard to get everything.
Repository: zhengfan2014/xbmc-kodi-private-china-addons
Branch: py2
Commit: 984856b358da
Files: 176
Total size: 1.3 MB

Directory structure:
gitextract_lwjw29km/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── ------.md
│   │   ├── -----.md
│   │   ├── ----.md
│   │   └── feature_request.md
│   ├── auto.py
│   └── workflows/
│       └── auto.yml
├── LICENSE
├── README.md
├── addons.xml
├── addons.xml.md5
├── metadata.douban.com.python/
│   ├── LICENSE.txt
│   ├── README.md
│   ├── addon.xml
│   ├── python/
│   │   ├── lib/
│   │   │   ├── __init__.py
│   │   │   └── tmdbscraper/
│   │   │       ├── __init__.py
│   │   │       ├── api_utils.py
│   │   │       ├── fanarttv.py
│   │   │       ├── imdbratings.py
│   │   │       ├── tmdb.py
│   │   │       ├── tmdbapi.py
│   │   │       └── traktratings.py
│   │   ├── scraper.py
│   │   ├── scraper_config.py
│   │   └── scraper_datahelper.py
│   └── resources/
│       ├── language/
│       │   └── Chinese (Simple)/
│       │       └── strings.po
│       └── settings.xml
├── plugin.audio.jsososo/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   ├── Chinese (Simple)/
│       │   │   └── strings.po
│       │   └── English/
│       │       └── strings.xml
│       ├── lib/
│       │   └── __init__.py
│       └── settings.xml
├── plugin.video.acfun/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.bangumi/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           ├── __init__.py
│           ├── zhcdict.json
│           └── zhconv.py
├── plugin.video.bilibili/
│   ├── addon.py
│   ├── addon.xml
│   ├── danmuku.py
│   ├── readme.md
│   ├── resources/
│   │   ├── __init__.py
│   │   ├── language/
│   │   │   ├── Chinese (Simple)/
│   │   │   │   └── strings.po
│   │   │   ├── English/
│   │   │   │   └── strings.xml
│   │   │   ├── resource.language.en_us/
│   │   │   │   └── strings.po
│   │   │   └── resource.language.zh_cn/
│   │   │       └── strings.po
│   │   ├── lib/
│   │   │   └── __init__.py
│   │   └── settings.xml
│   └── xml2ass.py
├── plugin.video.bimibimi[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.changku/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.cine/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.clicli[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.huanxi/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.kaiyan/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.medicalvideo/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.pengpai[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.reallive/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.skypixel/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.taptap/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.vid/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.weibotv/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.xigua[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.xinpianchang/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── service.subtitles.acfun/
│   ├── addon.xml
│   ├── readme.md
│   ├── resources/
│   │   └── lib/
│   │       ├── __init__.py
│   │       └── xml2ass.py
│   └── service.py
├── service.subtitles.bilibili/
│   ├── addon.xml
│   ├── readme.md
│   ├── resources/
│   │   └── lib/
│   │       ├── __init__.py
│   │       └── xml2ass.py
│   └── service.py
└── step1/
    ├── README.MD
    ├── acfun-rank-list.py
    ├── acfun-video.py
    ├── bangumi.py
    ├── bilibili-all-list.py
    ├── bilibili-bangumi-list.py
    ├── bilibili-rank-list.py
    ├── bilibili-video-api.py
    ├── bilibili-video-list.py
    ├── kaiyan.py
    ├── livideo.py
    ├── pengpai.py
    ├── taptap.py
    ├── weibo.py
    ├── weibomiaopai的js加密算法破解.py
    ├── 医学卫视.py
    ├── 国土公开课.py
    └── 新片场和场库.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================

custom: ["afdian.net/@zhengfan2014", "paypal.me/nxsoft"]


================================================
FILE: .github/ISSUE_TEMPLATE/------.md
================================================
---
name: "\U0001F308功能要求"
about: 为这个项目提出一个想法
title: ''
labels: ''
assignees: ''

---

**您的功能请求是否与问题有关? 请描述**
清楚简洁地说明问题所在

**描述您想要的解决方案**
对您想要发生的事情的简洁明了的描述

**描述您考虑过的替代方案**
对您考虑过的所有替代解决方案或功能的简洁明了的描述

**其他背景**
在此处添加有关功能请求的其他任何上下文或屏幕截图


================================================
FILE: .github/ISSUE_TEMPLATE/-----.md
================================================
---
name: "❌错误报告"
about: 创建报告以帮助我们改进
title: ''
labels: ''
assignees: ''

---

**描述错误**
清楚简明地描述错误是什么

**重现**
重现行为的步骤:
1. 去 '...'
2. 点击 '....'
3. 划到 '....'
4. 出错

**预期行为**
对您期望发生的事情的简洁明了的描述

**屏幕截图**
如果适用,请添加屏幕截图以帮助解释您的问题

**设备信息**
 - 设备: [e.g. 电脑,手机,电视盒子,xbox]
 - 系统: [e.g.Win10,MacOS Big Sur]
 - Kodi 版本 [e.g. kodi18, kodi17]


**其他**
在此处添加有关该问题的任何其他上下文


================================================
FILE: .github/ISSUE_TEMPLATE/----.md
================================================
---
name: 功能要求
about: 为这个项目提出一个想法
title: ''
labels: ''
assignees: ''

---

**您的功能请求是否与问题有关? 请描述**
清楚简洁地说明问题所在

**描述您想要的解决方案**
对您想要发生的事情的简洁明了的描述

**描述您考虑过的替代方案**
对您考虑过的所有替代解决方案或功能的简洁明了的描述

**其他背景**
在此处添加有关功能请求的其他任何上下文或屏幕截图


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/auto.py
================================================
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import re
import xml.etree.cElementTree as et
import zipfile
import shutil
import hashlib


workpath = '/workdir/python2/'

addons_xml = et.Element('addons')

# 匹配所有需要处理的kodi插件
for pluginname in os.listdir(workpath):
    if re.search('\[停止更新\]|video.vid|bangumi|cine|reallive', pluginname):
        # 跳过停止更新的项目
        pass
    elif re.search('metadata.*', pluginname) or re.search('plugin.*', pluginname) or re.search('service.*', pluginname):
        # 读取xml获取版本
        parser = et.parse(workpath + "/" + pluginname + "/addon.xml")
        root = parser.getroot()
        version = root.attrib['version']
        # 创建repo
        basepath = workpath + "/repo/" + pluginname + '/'
        if not os.path.exists(basepath):
            os.makedirs(basepath)
        # 压缩
        zippath = basepath + str(pluginname) + '-' + version + '.zip'
        f = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
        for dirpath, dirnames, filenames in os.walk(workpath + '/' + pluginname):
            # 这一句很重要,不replace的话,就从根目录开始复制
            fpath = dirpath.replace(workpath + '/', '')
            fpath = fpath and fpath + os.sep or ''  # 这句话理解我也点郁闷,实现当前文件夹以及包含的所有文件的压缩
            for filename in filenames:
                f.write(os.path.join(dirpath, filename), fpath+filename)
        print(pluginname + '压缩成功')
        f.close()
        # 拷贝icon
        shutil.copy(workpath + '/' + str(pluginname) + '/icon.png', basepath + 'icon.png')
        # 合并xml
        addons_xml.append(root)
# 输出addons.xml
tree = et.ElementTree(addons_xml)
tree.write(workpath + '/addons.xml', "UTF-8",xml_declaration=True)
# 生成addons.xml.md5
f = open(workpath + '/addons.xml')
m2 = hashlib.md5()
text = f.read()
m2.update(text)
f.close()
with open(workpath + '/addons.xml.md5','w') as f: # 如果filename不存在会自动创建, 'w'表示写数据,写之前会清空文件中的原有数据!
    f.write(m2.hexdigest())
    f.close()

================================================
FILE: .github/workflows/auto.yml
================================================
name: kodi 插件自动化
on: push

jobs: 
  my-job: 
    runs-on: ubuntu-latest
    name: 打包Kodi插件并自动更新插件库
    steps: 
    - name: 初始化环境
      run: |
        sudo mkdir -p /workdir
        sudo chown $USER:$GROUPS /workdir
        sudo apt install python
    - name: 克隆代码
      working-directory: /workdir
      run: |
        df -hT $PWD
        git clone https://github.com/zhengfan2014/xbmc-kodi-private-china-addons -b py2 python2
    - name: 运行python
      run: |
        python /workdir/python2/.github/auto.py
    - name: Commit 文件
      run: |
        cd /workdir/python2
        git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
        git config --local user.name "github-actions[bot]"
        git add repo
        git add addons.xml
        git add addons.xml.md5
        git commit -m "[bot] 自动打包插件并推送到存储库"
        git init
    - name: Push 到 Github
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: py2
        repository: zhengfan2014/xbmc-kodi-private-china-addons
        directory: /workdir/python2

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 zhengfan2014

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# zhengfan2014的kodi插件仓库
![xbmc-kodi-private-china-addons](https://socialify.git.ci/zhengfan2014/xbmc-kodi-private-china-addons/image?description=1&font=Inter&forks=1&issues=1&language=1&owner=1&pattern=Circuit%20Board&pulls=1&stargazers=1&theme=Dark)

![kodi18测试通过](https://img.shields.io/badge/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83-kodi%2018-green)
[![酷安粉丝][coolapk]](http://www.coolapk.com/u/2864549) [![b站粉丝][bilibili]](https://space.bilibili.com/25818910)
[![爱发电本月收入][mon]](https://afdian.net/@zhengfan2014)
[![爱发电发电人数][once]](https://afdian.net/@zhengfan2014)

----

## 介绍

xbmc-kodi-private-china-addons 是一个存放由zhengfan2014编写和维护的Kodi插件的GitHub仓库。可以为Kodi增加播放Bilibili等视频网站和挂载弹幕等奇奇怪怪的功能。目前借助社区的力量慢速发展中,目前已适配数十个网站的音视频内容。

----

## 插件目录

### 视频插件

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ----
 plugin.video.bilibili | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.bilibili/icon.png" width = "50" height = "50"/><br>bilibili | 0.5.8 | 2021-02-18 | bilibili是国内知名的视频弹幕网站,这里有最及时的动漫新番,最棒的ACG氛围,最有创意的Up主。大家可以在这里找到许多欢乐
 plugin.video.taptap | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.taptap/icon.png" width = "50" height = "50"/><br>Taptap | 0.2.2 | 2021-02-17 | TapTap是一个推荐高品质手游的手游分享社区,实时同步全球各大应用市场游戏排行榜,与全球玩家共同交流并发掘高品质手游。每一款推荐游戏,都是由专业的测评团队从全球海量的游戏中精选而出,只为你提供好玩的手机游戏。
 plugin.video.acfun | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.acfun/icon.png" width = "50" height = "50"/><br>acfun | 0.2.3 | 2020-09-15 | AcFun是一家弹幕视频网站,致力于为每一个人带来欢乐
 plugin.video.changku | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.changku/icon.png" width = "50" height = "50"/><br>场库 | 0.1.0 | 2020-03-29 | 高品质短片分享平台,汇集优秀视频短片及微电影创作人,实时不断分享全球优秀视频短片,微电影
 plugin.video.huanxi | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.huanxi/icon.png" width = "50" height = "50"/><br>欢喜首映 | 0.1.0 | 2020-03-29 | 欢喜首映拥有王家卫、徐峥、陈可辛、宁浩、顾长卫、张一白、贾樟柯、张艺谋等巨匠影人为平台定制的大制作网剧、网络大电影,将视频播放与内容制作合二为一,首映厅首发好电影
 plugin.video.skypixel | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.skypixel/icon.png" width = "50" height = "50"/><br>天空之城 | 0.1.0 | 2020-03-29 | 世界各地的航拍摄影师、拍手叫绝的航拍作品与独具价值的航拍攻略。全世界的探索者们互相启发,乐在其中
 plugin.video.xinpianchang | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.xinpianchang/icon.png" width = "50" height = "50"/><br>新片场 | 0.1.0 | 2020-03-29 | 新片场汇聚全球原创优质视频及创作人,提供4K、无广告、无水印视频观看,专业的视频艺术学习教程,正版视觉素材交易等,与数百万创作人一起用作品打动世界
 plugin.video.weibotv | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.weibotv/icon.png" width = "50" height = "50"/><br>微博视频 | 0.1.1 | 2020-03-16 | 随时随地发现新鲜事!微博带你欣赏世界上每一个精彩瞬间,了解每一个幕后故事。
 plugin.video.kaiyan | <img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.kaiyan/icon.png" width = "50" height = "50"/><br>开眼 | 0.1.0 | 2020-03-10 | 精选视频推荐,每日大开眼界
 
 ----

### 音乐插件

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 plugin.audio.jsososo | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.audio.jsososo/icon.png" width = "50" height = "50"/><br>jsososo | 0.1.0 | 2020-05-15 |music.jsososo.com的音乐插件,播放你自己的网易云和QQ音乐歌单和日推

 ### 弹幕插件

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 service.subtitles.acfun | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.acfun/icon.png" width = "50" height = "50"/><br>Acfun 弹幕 | 0.1.1 | 2020-07-19 |获取并挂载acfun任意视频和番剧的弹幕,支持配合acfun插件显示弹幕,也可以用于本地nas上的番剧或者bangumi插件显示弹幕
  service.subtitles.bilibili | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.bilibili/icon.png" width = "50" height = "50"/><br>Bilibili 弹幕 | 0.1.1 | 2020-07-19 |获取并挂载b站任意视频和番剧的弹幕,支持配合b站插件显示弹幕,也可以用于本地nas上的番剧或者bangumi插件显示弹幕

----

### 原创插件

#### 番剧聚合

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 plugin.video.bangumi | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.bangumi/icon.png" width = "50" height = "50"/><br>bangumi | 0.2.1 | 2021-02-18 |模块化的小众番剧网站聚合插件,提供开发文档,让有python基础的用户无需学习kodi插件开发知识,为本插件快速适配番剧网站



----

#### 电影聚合

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 plugin.video.cine | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.cine/icon.png" width = "50" height = "50"/><br>cine | 0.2.0 | 2020-06-14 |模块化的小众电影/电视剧/综艺网站聚合插件,提供开发文档,让有python基础的用户无需学习kodi插件开发知识,为本插件快速适配电影网站



----

#### 新闻/自媒体聚合

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 plugin.video.vid | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.vid/icon.png" width = "50" height = "50"/><br>vid | 0.1.0 | 2020-05-03 |模块化的新闻/自媒体等单一视频网站聚合插件,提供开发文档,让有python基础的用户无需学习kodi插件开发知识,为本插件快速适配新闻/自媒体等网站



----

#### 直播聚合

插件目录              | 插件名 | 版本 | 最后更新 | 简介
 :------------------ | :----: | ---- | ---- | ---- 
 plugin.video.reallive | <img width = "200" height = "0"/><img src="https://cdn.jsdelivr.net/gh/zhengfan2014/xbmc-kodi-private-china-addons@py2/repo/plugin.video.reallive/icon.png" width = "50" height = "50"/><br>reallive | 0.1.1 | 2020-06-09 |模块化的直播网站聚合插件,让有python基础的用户无需学习kodi插件开发知识,为本插件快速适配各大直播网站

## 插件库(New)

Github:

Gitee:

## 下载&更新地址

### Github Action全自动打包(New)

国内 - Gitee:  
https://gitee.com/zhengfan2014/xbmc-kodi-private-china-addons/tree/master/latest

国外 - Github:  
https://github.com/zhengfan2014/xbmc-kodi-private-china-addons/tree/master/latest

### 手动打包

国内 - 爱发电  
https://afdian.net/@zhengfan2014

国外 - GitHub  
推荐,更新比较及时  
博客地址:https://zhengfan2014.github.io/

国内 - Gitee  
推荐,目前采用github action,两个博客内容会自动同步
博客地址:https://zhengfan2014.gitee.io/


## 捐赠作者
如果您觉得这些小作品对您有很大帮助的话,不妨给作品点一个小小的star,请作者喝一杯咖啡,您的支持也是作者维护插件库的动力  
爱发电:https://afdian.net/@zhengfan2014  
paypal:http://paypal.me/nxsoft


[coolapk]:https://img.shields.io/badge/dynamic/json?labelColor=11ab60&color=282c34&label=%E9%85%B7%E5%AE%89%20紫碧君&suffix=%20粉丝&query=%24.data.totalSubs&url=https%3A%2F%2Fapi.spencerwoo.com%2Fsubstats%2F%3Fsource%3Dcoolapk%26queryKey%3D2864549&logo=data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPjxkZWZzPjxzdHlsZS8+PC9kZWZzPjxwYXRoIGQ9Ik0xMjcuODkzIDQyNi42NjdjMjkuOTItNjYuOTg3IDk0LjUwNy0xMTYuNjk0IDE2Ni40LTEzMC4zNDcgNTUuNzg3LTkuNiAxMTIuOTYgNS4wNjcgMTYxLjkyIDMxLjk0N0M0OTcuNzYgMzQ5LjQ0IDUzNC40IDM3OC44OCA1NjcuOTQ3IDQxMS4wNGMtMTYuMTYgMTguNC0zOS4wOTQgMjguODUzLTU3LjQ5NCA0NC43NDctNDYuMTMzLTM4Ljg4LTk2LjY0LTc3LjcwNy0xNTcuOTczLTg3LjA5NC03OC45MzMtMTMuMTczLTE1OC41NiA0OS4yMjctMTcwLjUwNyAxMjcuMTQ3LTguNjkzIDQ1LjkyIDEwLjEzNCA5NC42NjcgNDUuMTc0IDEyNC45MDcgMzkuNjggMzQuOTg2IDk3LjIyNiA0NC41ODYgMTQ3LjYyNiAzMS4yNTMgNTcuNi0xMy45MiAxMDEuOTc0LTU3LjA2NyAxMzYuODU0LTEwMi43NzMgNTQuMDgtNzIuMTA3IDk5LjItMTUwLjQgMTQ3Ljg0LTIyNi4xMzQgMTMuOTItMTkuMTQ2IDQ3LjQxMy0xNy4yMjYgNTguNzIgMy44NCA2My42MjYgMTA5LjAxNCAxMjYuMDggMjE4LjcyIDE4OS42IDMyNy43ODcgNy41NzMgMTUuMDkzIDQuNDI2IDM1Ljc4Ny05LjYgNDYuMTMzLTEzLjA2NyAxMC42MTQtMzMuMzM0IDEwLjI0LTQ2LjEzNC0uNjkzYTk3MDY2LjU1OCA5NzA2Ni41NTggMCAwMS0yMjYuMTg2LTE2Mi43MmMxOC44OC0xNS4wNCAzOC40LTI5LjMzMyA1Ny45NzMtNDMuNDY3IDIzLjczMyAxMi45MDcgNDMuNzg3IDMzLjE3NCA2OS42IDQxLjY1NC0yMC4zNzMtMzkuNTc0LTQzLjYyNy03Ny43MDctNjYuMzQ3LTExNS45NDctNDIuNjY2IDU5LjE0Ny03Ny4wNjYgMTI0LjIxMy0xMjMuMTQ2IDE4MS4wNjdDNTE2IDY2My40NjcgNDQ4LjggNzE2Ljk2IDM2OC42NCA3MjguNDhjLTM4Ljg4IDMuNDEzLTc5LjMwNyA0LjIxMy0xMTYuMzczLTkuOTczLTUzLjQ5NC0xOS4xNDctMTAwLjMyLTU4LjcyLTEyNC41ODctMTEwLjU2LTI4LjIxMy01Ni4xMDctMjYuNzczLTEyNS4wMTQuMjEzLTE4MS4yOHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=&longCache=true

[bilibili]:https://img.shields.io/badge/dynamic/json?labelColor=FE7398&label=bilibili%20紫碧君&suffix=%20粉丝&query=%24.data.totalSubs&url=https%3A%2F%2Fapi.spencerwoo.com%2Fsubstats%2F%3Fsource%3Dbilibili%26queryKey%3D25818910&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAD7ElEQVR4nO2dW9WrMBCFK6ESkFAJSKiESqgEHCABCZWAhEpAAhL2ecik5dDc/pXLBDLfWnlqy0xmJ5BMQnq5CIIgCIIgCIIgCIIgCEIBAHQAemYfrgCunD6wAKAHsEKxALgx+bCQD8/S9tmgVqeDr1lLigDgZvDhXso+K9TyTBQRwRJ8AHjntl0Flh5QRAQK/mKxPeayWx2OXpBNBKiHvi34b7T2MC4pAvW6twR/RwkRKPizBN8CgEcuESj4Lwm+BwBjahEk+H8EwJRKhOaCDzW8e1JLfkUUH1NgmR3XmHffHR1l+72BSs8d7w8U+JDAnZERQMcV+CtUi7dNqFqibB4J7vtrq7xKCuAasbTMXCL4T+5aVk6+2xHUrWdhruAR6HIJcOeu2UHI8zyAe2ytWfEdWz9PVvQ8YAmIQ5dDAB9LFsMVAv8oMO2zAGrC5WNIarRiAuKR9jYEd9pY08aa6uUzIHGRdkgKd8pY0yc1WjEBAqypDYoAG0QAZkQAZkQAZkQAZk4vANQenjsSzS3I/wcSbXU5jQBUkRtdf4Rar90v8kSv3+I3ffCCSpk8I/w+lgDkdI/v2rEp2CaiWm1AsDQLlDAD+dlFXLMeAaCSeLZdaSFE5VUQNot38cKuEeBgAsSuG0flVZBmEanbXfNQAsS0fgBYIn2fIu3/BBMHEyBmDXlFfA8IzeHb+Ems4WAChKykrVA9ZfsQTL57jXzRg4A5wC/A8N4ADiZAZwm2XjW75Qh2KOTfA0p4kygPw28OJcCVgn3nDnYo2EwEYRgGH0qAMyICMCMCMCMCMCMCMCMCMCMCfP3qwHDOQ4AAUekTk8FaBRihJnZdYbvtCGC7LvmkM63GjVDINPFrQgCq5ETXfmMzI90FXzPvfqt7x4rEu/ZaEcCUxFvgz2zO+BUn6UkoaEEAsptiMSX5e8FoRYCN7cVgb4Vq7U/H50Pq4JNP7Qiw8UFnJwcK+tXy+Wj6PLEvPgHSHv5UgwA1IQIwwyFAyLJin9RoxYgAzAQIkPwNmf26busC+OIx5TDqo5nDT+F/SS/9CYzwb+No49zNy2evkYv0LywGGAXUvp6eSneycqOic0w20k7CNgKE7jJunSGLACTCxF27ylmQc98T5MQUH49swd+I0HPXslLKnT0N+wnkrTKi9JZL/L9i1SorMmdeQ4TQQ7OFMxIMzGD45w8nUL1im7efENZLJpgPSw0pfz0cdt4U3230Td/Tvx2R6d2FrHhEWLkq5PELOMsRPHCPnAZGv1xJteL7jbJiaW3sB2nDvPC/osSYvjRQz4cJ6n7KO3rYQL7M+L6nVtfDVRAEQRAEQRAEQRAEIZ5/SAXmdfXaoQsAAAAASUVORK5CYII=&color=282c34&longCache=true

[mon]:https://img.shields.io/badge/dynamic/json?label=本月收入&query=%24.data.totalSubs&url=https%3A%2F%2Fapi.spencerwoo.com%2Fsubstats%2F%3Fsource%3DafdianIncome%26queryKey%3Dzhengfan2014&prefix=%EF%BF%A5%20&suffix=%20%E6%AF%8F%E6%9C%88&labelColor=946ce6&color=282c34&longCache=true

[once]:https://img.shields.io/badge/dynamic/json?label=%E7%88%B1%E5%8F%91%E7%94%B5&query=%24.data.totalSubs&url=https%3A%2F%2Fapi.spencerwoo.com%2Fsubstats%2F%3Fsource%3DafdianFans%26queryKey%3Dzhengfan2014&suffix=%20%E5%8F%91%E7%94%B5%E4%BA%BA%E6%AC%A1%20%2F%20%E6%9C%88&labelColor=946ce6&color=282c34&longCache=true

================================================
FILE: addons.xml
================================================
<?xml version='1.0' encoding='UTF-8'?>
<addons><addon id="metadata.douban.com.python" name="豆瓣刮削器Python" provider-name="zhengfan" version="0.1.1">
  <requires>
    <import addon="xbmc.metadata" version="2.1.0" />
    <import addon="xbmc.python" version="2.26.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
    <import addon="script.module.beautifulsoup4" version="4.5.3" />
    <import addon="script.module.requests" version="2.19.1" />
    <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="python/scraper.py" point="xbmc.metadata.scraper.movies" />
  <extension point="xbmc.addon.metadata">

    <summary>豆瓣刮削器Python</summary>
    <description>豆瓣电影提供最新的电影介绍及评论包括上映影片的影讯查询及购票服务。你可以记录想看、在看和看过的电影电视剧,顺便打分、写影评。根据你的口味,豆瓣电影会推荐好电影给你。</description>
    <platform>all</platform>
    <language />
    <assets>
      <icon>icon.png</icon>
    </assets>
  </extension>
</addon><addon id="plugin.video.acfun" name="Acfun" provider-name="zhengfan" version="0.2.3">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>AcFun是一家弹幕视频网站,致力于为每一个人带来欢乐。</description>
  </extension>
</addon><addon id="plugin.video.weibotv" name="微博视频" provider-name="zhengfan" version="0.1.1">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>随时随地发现新鲜事!微博带你欣赏世界上每一个精彩瞬间,了解每一个幕后故事。</description>
  </extension>
</addon><addon id="plugin.video.medicalvideo" name="医学微视" provider-name="zhengfan" version="0.1.0">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>医学微视是配合卫健委宣传司《全民健康素养促进活动》精神,在中华医学会科学普及分会指导下,由中国医学科学院健康科普中心监制而实施,以“让人们多了解一点医学知识,健康就多一份保障”的宗旨,团队只想把医学微视做得更好,让更多的患者能共享到医学专家们多年积累的宝贵经验和知识,能对需要的人有一点点帮助</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="service.subtitles.acfun" name="Acfun 弹幕" provider-name="xodidox,zhengfan,shaolin-kongfu" version="0.1.1">
    <requires>
        <import addon="xbmc.python" version="2.1.0" />
        <import addon="script.module.requests" version="1.1.0" />
        <import addon="script.module.beautifulsoup4" version="4.3.2" />
        <import addon="vfs.rar" version="2.3.0" />
    </requires>
    <extension library="service.py" point="xbmc.subtitle.module" />
    <extension point="xbmc.addon.metadata">
        <summary lang="zh">Acfun 弹幕插件</summary>
        <description lang="zh">从 Acfun 下载弹幕</description>
        <assets>
            <icon>icon.png</icon>
            <clearlogo>logo.png</clearlogo>
            <fanart>resources/media/fanart.jpg</fanart>
            <screenshot>resources/media/screenshot_1.png</screenshot>
            <screenshot>resources/media/screenshot_2.png</screenshot>
            <screenshot>resources/media/screenshot_3.png</screenshot>
        </assets>
        <news />
    </extension>
</addon><addon id="plugin.audio.jsososo" name="Jsososo" provider-name="zhengfan" version="0.1.1">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>audio</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>网易云音乐,QQ音乐,咪咕音乐聚合插件,API 1000%使用music.jsososo.com的服务</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="plugin.video.xinpianchang" name="新片场" provider-name="zhengfan" version="0.1.1">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>新片场汇聚全球原创优质视频及创作人,提供4K、无广告、无水印视频观看,专业的视频艺术学习教程,正版视觉素材交易等,与数百万创作人一起用作品打动世界</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="plugin.video.taptap" name="Taptap" provider-name="zhengfan" version="0.2.2">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>TapTap是一个推荐高品质手游的手游分享社区,实时同步全球各大应用市场游戏排行榜,与全球玩家共同交流并发掘高品质手游。每一款推荐游戏,都是由专业的测评团队从全球海量的游戏中精选而出,只为你提供好玩的手机游戏。</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="plugin.video.kaiyan" name="开眼" provider-name="zhengfan" version="0.1.0">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>精选视频推荐,每日大开眼界</description>
  </extension>
</addon><addon id="plugin.video.huanxi" name="欢喜首映" provider-name="zhengfan" version="0.1.0">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>欢喜首映拥有王家卫、徐峥、陈可辛、宁浩、顾长卫、张一白、贾樟柯、张艺谋等巨匠影人为平台定制的大制作网剧、网络大电影,将视频播放与内容制作合二为一,首映厅首发好电影</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="plugin.video.changku" name="场库" provider-name="zhengfan" version="0.1.0">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>高品质短片分享平台,汇集优秀视频短片及微电影创作人,实时不断分享全球优秀视频短片,微电影</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon><addon id="plugin.video.bilibili" name="Bilibili" provider-name="zhengfan,shaolin-kongfu,YingjieSong,ArchieMeng" version="0.5.8">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension library="danmuku.py" point="xbmc.python.module" />
  <extension library="xml2ass.py" point="xbmc.python.module" />
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>bilibili是国内知名的视频弹幕网站,这里有最及时的动漫新番,最棒的ACG氛围,最有创意的Up主。大家可以在这里找到许多欢乐</description>
  </extension>
</addon><addon id="service.subtitles.bilibili" name="Bilibili 弹幕" provider-name="xodidox,zhengfan,shaolin-kongfu" version="0.1.1">
    <requires>
        <import addon="xbmc.python" version="2.1.0" />
        <import addon="script.module.requests" version="1.1.0" />
        <import addon="script.module.beautifulsoup4" version="4.3.2" />
        <import addon="vfs.rar" version="2.3.0" />
    </requires>
    <extension library="service.py" point="xbmc.subtitle.module" />
    <extension point="xbmc.addon.metadata">
        <summary lang="zh">哔哩哔哩 弹幕插件</summary>
        <description lang="zh">从 哔哩哔哩 下载弹幕</description>
        <assets>
            <icon>icon.png</icon>
            <clearlogo>logo.png</clearlogo>
            <fanart>resources/media/fanart.jpg</fanart>
            <screenshot>resources/media/screenshot_1.png</screenshot>
            <screenshot>resources/media/screenshot_2.png</screenshot>
            <screenshot>resources/media/screenshot_3.png</screenshot>
        </assets>
        <news />
    </extension>
</addon><addon id="plugin.video.skypixel" name="天空之城" provider-name="zhengfan" version="0.1.0">
  <requires>
    <import addon="xbmc.python" version="2.1.0" />
    <import addon="script.module.xbmcswift2" version="2.4.0" />
  <import addon="script.module.beautifulsoup4" version="4.5.3" />
  <import addon="script.module.requests" version="2.19.1" />
  <import addon="script.module.html5lib" version="0.999.0" />
  </requires>
  <extension library="addon.py" point="xbmc.python.pluginsource">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language />
    <description>世界各地的航拍摄影师、拍手叫绝的航拍作品与独具价值的航拍攻略。全世界的探索者们互相启发,乐在其中</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon></addons>

================================================
FILE: addons.xml.md5
================================================
4e63ef3b358c798d9253b01d3d5f5c1c

================================================
FILE: metadata.douban.com.python/LICENSE.txt
================================================
Valid-License-Identifier: GPL-2.0-or-later
SPDX-URL:https://spdx.org/licenses/GPL-2.0-or-later.html
Usage-Guide:
  To use the GNU General Public License v2.0 or later put the following SPDX
  tag/value pair into a comment according to the placement guidelines in
  the licensing rules documentation:
    SPDX-License-Identifier: GPL-2.0-or-later
License-Text:

GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc. 

51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA

Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share
and change it. By contrast, the GNU General Public License is intended to
guarantee your freedom to share and change free software--to make sure the
software is free for all its users. This General Public License applies to
most of the Free Software Foundation's software and to any other program whose
authors commit to using it. (Some other Free Software Foundation software
is covered by the GNU Lesser General Public License instead.) You can apply
it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the freedom
to distribute copies of free software (and charge for this service if you
wish), that you receive source code or can get it if you want it, that you
can change the software or use pieces of it in new free programs; and that
you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to
deny you these rights or to ask you to surrender the rights. These restrictions
translate to certain responsibilities for you if you distribute copies of
the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or
for a fee, you must give the recipients all the rights that you have. You
must make sure that they, too, receive or can get the source code. And you
must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2)
offer you this license which gives you legal permission to copy, distribute
and/or modify the software.

Also, for each author's protection and ours, we want to make certain that
everyone understands that there is no warranty for this free software. If
the software is modified by someone else and passed on, we want its recipients
to know that what they have is not the original, so that any problems introduced
by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We
wish to avoid the danger that redistributors of a free program will individually
obtain patent licenses, in effect making the program proprietary. To prevent
this, we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification
follow.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice
placed by the copyright holder saying it may be distributed under the terms
of this General Public License. The "Program", below, refers to any such program
or work, and a "work based on the Program" means either the Program or any
derivative work under copyright law: that is to say, a work containing the
Program or a portion of it, either verbatim or with modifications and/or translated
into another language. (Hereinafter, translation is included without limitation
in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered
by this License; they are outside its scope. The act of running the Program
is not restricted, and the output from the Program is covered only if its
contents constitute a work based on the Program (independent of having been
made by running the Program). Whether that is true depends on what the Program
does.

1. You may copy and distribute verbatim copies of the Program's source code
as you receive it, in any medium, provided that you conspicuously and appropriately
publish on each copy an appropriate copyright notice and disclaimer of warranty;
keep intact all the notices that refer to this License and to the absence
of any warranty; and give any other recipients of the Program a copy of this
License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you
may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it,
thus forming a work based on the Program, and copy and distribute such modifications
or work under the terms of Section 1 above, provided that you also meet all
of these conditions:

a) You must cause the modified files to carry prominent notices stating that
you changed the files and the date of any change.

b) You must cause any work that you distribute or publish, that in whole or
in part contains or is derived from the Program or any part thereof, to be
licensed as a whole at no charge to all third parties under the terms of this
License.

c) If the modified program normally reads commands interactively when run,
you must cause it, when started running for such interactive use in the most
ordinary way, to print or display an announcement including an appropriate
copyright notice and a notice that there is no warranty (or else, saying that
you provide a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this License.
(Exception: if the Program itself is interactive but does not normally print
such an announcement, your work based on the Program is not required to print
an announcement.)

These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Program, and can be reasonably
considered independent and separate works in themselves, then this License,
and its terms, do not apply to those sections when you distribute them as
separate works. But when you distribute the same sections as part of a whole
which is a work based on the Program, the distribution of the whole must be
on the terms of this License, whose permissions for other licensees extend
to the entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest your
rights to work written entirely by you; rather, the intent is to exercise
the right to control the distribution of derivative or collective works based
on the Program.

In addition, mere aggregation of another work not based on the Program with
the Program (or with a work based on the Program) on a volume of a storage
or distribution medium does not bring the other work under the scope of this
License.

3. You may copy and distribute the Program (or a work based on it, under Section
2) in object code or executable form under the terms of Sections 1 and 2 above
provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable source code,
which must be distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,

b) Accompany it with a written offer, valid for at least three years, to give
any third party, for a charge no more than your cost of physically performing
source distribution, a complete machine-readable copy of the corresponding
source code, to be distributed under the terms of Sections 1 and 2 above on
a medium customarily used for software interchange; or,

c) Accompany it with the information you received as to the offer to distribute
corresponding source code. (This alternative is allowed only for noncommercial
distribution and only if you received the program in object code or executable
form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making
modifications to it. For an executable work, complete source code means all
the source code for all modules it contains, plus any associated interface
definition files, plus the scripts used to control compilation and installation
of the executable. However, as a special exception, the source code distributed
need not include anything that is normally distributed (in either source or
binary form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component itself
accompanies the executable.

If distribution of executable or object code is made by offering access to
copy from a designated place, then offering equivalent access to copy the
source code from the same place counts as distribution of the source code,
even though third parties are not compelled to copy the source along with
the object code.

4. You may not copy, modify, sublicense, or distribute the Program except
as expressly provided under this License. Any attempt otherwise to copy, modify,
sublicense or distribute the Program is void, and will automatically terminate
your rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses terminated
so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed
it. However, nothing else grants you permission to modify or distribute the
Program or its derivative works. These actions are prohibited by law if you
do not accept this License. Therefore, by modifying or distributing the Program
(or any work based on the Program), you indicate your acceptance of this License
to do so, and all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program),
the recipient automatically receives a license from the original licensor
to copy, distribute or modify the Program subject to these terms and conditions.
You may not impose any further restrictions on the recipients' exercise of
the rights granted herein. You are not responsible for enforcing compliance
by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement
or for any other reason (not limited to patent issues), conditions are imposed
on you (whether by court order, agreement or otherwise) that contradict the
conditions of this License, they do not excuse you from the conditions of
this License. If you cannot distribute so as to satisfy simultaneously your
obligations under this License and any other pertinent obligations, then as
a consequence you may not distribute the Program at all. For example, if a
patent license would not permit royalty-free redistribution of the Program
by all those who receive copies directly or indirectly through you, then the
only way you could satisfy both it and this License would be to refrain entirely
from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply and
the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents
or other property right claims or to contest validity of any such claims;
this section has the sole purpose of protecting the integrity of the free
software distribution system, which is implemented by public license practices.
Many people have made generous contributions to the wide range of software
distributed through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing to
distribute software through any other system and a licensee cannot impose
that choice.

This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain
countries either by patents or by copyrighted interfaces, the original copyright
holder who places the Program under this License may add an explicit geographical
distribution limitation excluding those countries, so that distribution is
permitted only in or among countries not thus excluded. In such case, this
License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of
the General Public License from time to time. Such new versions will be similar
in spirit to the present version, but may differ in detail to address new
problems or concerns.

Each version is given a distinguishing version number. If the Program specifies
a version number of this License which applies to it and "any later version",
you have the option of following the terms and conditions either of that version
or of any later version published by the Free Software Foundation. If the
Program does not specify a version number of this License, you may choose
any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs
whose distribution conditions are different, write to the author to ask for
permission. For software which is copyrighted by the Free Software Foundation,
write to the Free Software Foundation; we sometimes make exceptions for this.
Our decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing and reuse
of software generally.

   NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible
use to the public, the best way to achieve this is to make it free software
which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach
them to the start of each source file to most effectively convey the exclusion
of warranty; and each file should have at least the "copyright" line and a
pointer to where the full notice is found.

<one line to give the program's name and an idea of what it does.>

Copyright (C) <yyyy> <name of author>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
Street, Fifth Floor, Boston, MA 02110-1301 , USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when
it starts in an interactive mode:

Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software,
and you are welcome to redistribute it under certain conditions; type `show
c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may be
called something other than `show w' and `show c'; they could even be mouse-clicks
or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your school,
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision'
(which makes passes at compilers) written by James Hacker.

< signature of Ty Coon > , 1 April 1989 Ty Coon, President of Vice This General
Public License does not permit incorporating your program into proprietary
programs. If your program is a subroutine library, you may consider it more
useful to permit linking proprietary applications with the library. If this
is what you want to do, use the GNU Lesser General Public License instead
of this License.


================================================
FILE: metadata.douban.com.python/README.md
================================================
## The Movie Database Python scraper for Kodi

This is early work on a Python movie scraper for Kodi.

### Manual search by IMDB / TMDB ID
When manually searching you can enter an IMDB or TMDB ID to pull up an exact movie result.
To search by TMDB enter "tmdb/" then the ID, like "tmdb/11". To search by IMDB ID enter it directly.

## Development info

### How to run unit tests

`python -m unittest discover -v` from the main **metadata.themoviedb.org.python** directory.
Python 3 only.


================================================
FILE: metadata.douban.com.python/addon.xml
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="metadata.douban.com.python" name="豆瓣刮削器Python" version="0.1.1" provider-name="zhengfan">
  <requires>
    <import addon="xbmc.metadata" version="2.1.0"/>
    <import addon="xbmc.python" version="2.26.0"/>
    <import addon="script.module.xbmcswift2" version="2.4.0"/>
    <import addon="script.module.beautifulsoup4" version="4.5.3"/>
    <import addon="script.module.requests" version="2.19.1"/>
    <import addon="script.module.html5lib" version="0.999.0"/>
  </requires>
  <extension point="xbmc.metadata.scraper.movies" library="python/scraper.py"/>
  <extension point="xbmc.addon.metadata">

    <summary>豆瓣刮削器Python</summary>
    <description>豆瓣电影提供最新的电影介绍及评论包括上映影片的影讯查询及购票服务。你可以记录想看、在看和看过的电影电视剧,顺便打分、写影评。根据你的口味,豆瓣电影会推荐好电影给你。</description>
    <platform>all</platform>
    <language></language>
    <assets>
      <icon>icon.png</icon>
    </assets>
  </extension>
</addon>


================================================
FILE: metadata.douban.com.python/python/lib/__init__.py
================================================


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/__init__.py
================================================

def get_imdb_id(uniqueids):
    imdb_id = uniqueids.get('imdb')
    if not imdb_id or not imdb_id.startswith('tt'):
        return None
    return imdb_id

# example format for scraper results
_ScraperResults = {
    'info',
    'ratings',
    'uniqueids',
    'cast',
    'available_art',
    'error',
    'warning' # not handled
}


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/api_utils.py
================================================
# coding: utf-8
#
# Copyright (C) 2020, Team Kodi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

"""Functions to interact with various web site APIs."""

from __future__ import absolute_import, unicode_literals

import json, xbmc
# from pprint import pformat
try: #PY2 / PY3
    from urllib2 import Request, urlopen
    from urllib2 import URLError
    from urllib import urlencode
except ImportError:
    from urllib.request import Request, urlopen
    from urllib.error import URLError
    from urllib.parse import urlencode
try:
    from typing import Text, Optional, Union, List, Dict, Any  # pylint: disable=unused-import
    InfoType = Dict[Text, Any]  # pylint: disable=invalid-name
except ImportError:
    pass

HEADERS = {}


def set_headers(headers):
    HEADERS.update(headers)


def load_info(url, params=None, default=None, resp_type = 'json'):
    # type: (Text, Optional[Dict[Text, Union[Text, List[Text]]]]) -> Union[dict, list]
    """
    Load info from external api

    :param url: API endpoint URL
    :param params: URL query params
    :default: object to return if there is an error
    :resp_type: what to return to the calling function
    :return: API response or default on error
    """
    theerror = ''
    if params:
        url = url + '?' + urlencode(params)
    xbmc.log('Calling URL "{}"'.format(url), xbmc.LOGDEBUG)
    req = Request(url, headers=HEADERS)
    try:
        response = urlopen(req)
    except URLError as e:
        if hasattr(e, 'reason'):
            theerror = {'error': 'failed to reach the remote site\nReason: {}'.format(e.reason)}
        elif hasattr(e, 'code'):
            theerror = {'error': 'remote site unable to fulfill the request\nError code: {}'.format(e.code)}
        if default is not None:
            return default
        else:
            return theerror
    if resp_type.lower() == 'json':
        resp = json.loads(response.read().decode('utf-8'))
    else:
        resp = response.read().decode('utf-8')
    # xbmc.log('the api response:\n{}'.format(pformat(resp)), xbmc.LOGDEBUG)
    return resp


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/fanarttv.py
================================================
from . import api_utils
try:
    from urllib import quote
except ImportError: # py2 / py3
    from urllib.parse import quote

API_KEY = '384afe262ee0962545a752ff340e3ce4'
API_URL = 'https://webservice.fanart.tv/v3/movies/{}'

ARTMAP = {
    'movielogo': 'clearlogo',
    'hdmovielogo': 'clearlogo',
    'hdmovieclearart': 'clearart',
    'movieart': 'clearart',
    'moviedisc': 'discart',
    'moviebanner': 'banner',
    'moviethumb': 'landscape',
    'moviebackground': 'fanart',
    'movieposter': 'poster'
}

def get_details(uniqueids, clientkey, language, set_tmdbid):
    media_id = _get_mediaid(uniqueids)
    if not media_id:
        return {}

    movie_data = _get_data(media_id, clientkey)
    movieset_data = _get_data(set_tmdbid, clientkey)
    if not movie_data and not movieset_data:
        return {}

    movie_art = {}
    movieset_art = {}
    if movie_data:
        movie_art = _parse_data(movie_data, language)
    if movieset_data:
        movieset_art = _parse_data(movieset_data, language)
        movieset_art = {'set.' + key: value for key, value in movieset_art.items()}

    available_art = movie_art
    available_art.update(movieset_art)

    return {'available_art': available_art}

def _get_mediaid(uniqueids):
    for source in ('tmdb', 'imdb', 'unknown'):
        if source in uniqueids:
            return uniqueids[source]

def _get_data(media_id, clientkey):
    headers = {'api-key': API_KEY}
    if clientkey:
        headers['client-key'] = clientkey
    api_utils.set_headers(headers)
    fanarttv_url = API_URL.format(media_id)
    return api_utils.load_info(fanarttv_url, default={})

def _parse_data(data, language):
    result = {}
    for arttype, artlist in data.items():
        if arttype not in ARTMAP:
            continue
        for image in artlist:
            image_lang = _get_imagelanguage(arttype, image)
            if image_lang and image_lang != language:
                continue

            generaltype = ARTMAP[arttype]
            if generaltype == 'poster' and not image_lang:
                generaltype = 'keyart'
            if artlist and generaltype not in result:
                result[generaltype] = []

            url = quote(image['url'], safe="%/:=&?~#+!$,;'@()*[]")
            resultimage = {'url': url, 'preview': url.replace('.fanart.tv/fanart/', '.fanart.tv/preview/')}
            result[generaltype].append(resultimage)

    return result

def _get_imagelanguage(arttype, image):
    if 'lang' not in image or arttype == 'moviebackground':
        return None
    if arttype in ('movielogo', 'hdmovielogo', 'hdmovieclearart', 'movieart', 'moviebanner',
            'moviethumb', 'moviedisc'):
        return image['lang'] if image['lang'] not in ('', '00') else 'en'
    # movieposter may or may not have a title and thus need a language
    return image['lang'] if image['lang'] not in ('', '00') else None


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/imdbratings.py
================================================
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2020, Team Kodi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# IMDb ratings based on code in metadata.themoviedb.org.python by Team Kodi
# pylint: disable=missing-docstring

import re
from . import api_utils
from . import get_imdb_id

IMDB_RATINGS_URL = 'https://www.imdb.com/title/{}/'
IMDB_RATING_REGEX = re.compile(r'itemprop="ratingValue".*?>.*?([\d.]+).*?<')
IMDB_VOTES_REGEX = re.compile(r'itemprop="ratingCount".*?>.*?([\d,]+).*?<')
IMDB_TOP250_REGEX = re.compile(r'Top Rated Movies #(\d+)')

def get_details(uniqueids):
    imdb_id = get_imdb_id(uniqueids)
    if not imdb_id:
        return {}
    votes, rating, top250 = _get_ratinginfo(imdb_id)
    return _assemble_imdb_result(votes, rating, top250)

def _get_ratinginfo(imdb_id):
    response = api_utils.load_info(IMDB_RATINGS_URL.format(imdb_id), default = '', resp_type='text')
    return _parse_imdb_result(response)

def _assemble_imdb_result(votes, rating, top250):
    result = {}
    if top250:
        result['info'] = {'top250': top250}
    if votes and rating:
        result['ratings'] = {'imdb': {'votes': votes, 'rating': rating}}
    return result

def _parse_imdb_result(input_html):
    rating = _parse_imdb_rating(input_html)
    votes = _parse_imdb_votes(input_html)
    top250 = _parse_imdb_top250(input_html)

    return votes, rating, top250

def _parse_imdb_rating(input_html):
    match = re.search(IMDB_RATING_REGEX, input_html)
    if (match):
        return float(match.group(1))
    return None

def _parse_imdb_votes(input_html):
    match = re.search(IMDB_VOTES_REGEX, input_html)
    if (match):
        return int(match.group(1).replace(',', ''))
    return None

def _parse_imdb_top250(input_html):
    match = re.search(IMDB_TOP250_REGEX, input_html)
    if (match):
        return int(match.group(1))
    return None


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/tmdb.py
================================================
from datetime import datetime, timedelta
from . import tmdbapi


class TMDBMovieScraper(object):
    def __init__(self, url_settings, language, certification_country):
        self.url_settings = url_settings
        self.language = language
        self.certification_country = certification_country
        self._urls = None

    @property
    def urls(self):
        if not self._urls:
            self._urls = _load_base_urls(self.url_settings)
        return self._urls

    def search(self, title, year=None):
        search_media_id = _parse_media_id(title)
        if search_media_id:
            if search_media_id['type'] == 'tmdb':
                result = _get_movie(search_media_id['id'], self.language, True)
                result = [result]
            else:
                response = tmdbapi.find_movie_by_external_id(search_media_id['id'], language=self.language)
                theerror = response.get('error')
                if theerror:
                    return 'error: {}'.format(theerror)
                result = response.get('movie_results')
            if 'error' in result:
                return result
        else:
            response = tmdbapi.search_movie(query=title, year=year, language=self.language)
            theerror = response.get('error')
            if theerror:
                return 'error: {}'.format(theerror)
            result = response['results']
        urls = self.urls

        def is_best(item):
            return item['title'].lower() == title and (
                not year or item.get('release_date', '').startswith(year))
        if result and not is_best(result[0]):
            best_first = next((item for item in result if is_best(item)), None)
            if best_first:
                result = [best_first] + [item for item in result if item is not best_first]

        for item in result:
            if item.get('poster_path'):
                item['poster_path'] = urls['preview'] + item['poster_path']
            if item.get('backdrop_path'):
                item['backdrop_path'] = urls['preview'] + item['backdrop_path']
        return result

    def get_details(self, uniqueids):
        media_id = uniqueids.get('tmdb') or uniqueids.get('imdb')
        details = self._gather_details(media_id)
        if not details:
            return None
        if details.get('error'):
            return details
        return self._assemble_details(**details)

    def _gather_details(self, media_id):
        movie = _get_movie(media_id, self.language)
        if not movie or movie.get('error'):
            return movie

        # don't specify language to get English text for fallback
        movie_fallback = _get_movie(media_id)

        collection = _get_moviecollection(movie['belongs_to_collection'].get('id'), self.language) if \
            movie['belongs_to_collection'] else None
        collection_fallback = _get_moviecollection(movie['belongs_to_collection'].get('id')) if \
            movie['belongs_to_collection'] else None

        return {'movie': movie, 'movie_fallback': movie_fallback, 'collection': collection,
            'collection_fallback': collection_fallback}

    def _assemble_details(self, movie, movie_fallback, collection, collection_fallback):
        info = {
            'title': movie['title'],
            'originaltitle': movie['original_title'],
            'plot': movie.get('overview') or movie_fallback.get('overview'),
            'tagline': movie.get('tagline') or movie_fallback.get('tagline'),
            'studio': _get_names(movie['production_companies']),
            'genre': _get_names(movie['genres']),
            'country': _get_names(movie['production_countries']),
            'credits': _get_cast_members(movie['casts'], 'crew', 'Writing', ['Screenplay', 'Writer', 'Author']),
            'director': _get_cast_members(movie['casts'], 'crew', 'Directing', ['Director']),
            'premiered': movie['release_date'],
            'tag': _get_names(movie['keywords']['keywords'])
        }

        if 'countries' in movie['releases']:
            certcountry = self.certification_country.upper()
            for country in movie['releases']['countries']:
                if country['iso_3166_1'] == certcountry and country['certification']:
                    info['mpaa'] = country['certification']
                    break

        trailer = _parse_trailer(movie.get('trailers', {}), movie_fallback.get('trailers', {}))
        if trailer:
            info['trailer'] = trailer
        if collection:
            info['set'] = collection.get('name') or collection_fallback.get('name')
            info['setoverview'] = collection.get('overview') or collection_fallback.get('overview')
        if movie.get('runtime'):
            info['duration'] = movie['runtime'] * 60

        ratings = {'themoviedb': {'rating': float(movie['vote_average']), 'votes': int(movie['vote_count'])}}
        uniqueids = {'tmdb': movie['id'], 'imdb': movie['imdb_id']}
        cast = [{
                'name': actor['name'],
                'role': actor['character'],
                'thumbnail': self.urls['original'] + actor['profile_path']
                    if actor['profile_path'] else "",
                'order': actor['order']
            }
            for actor in movie['casts'].get('cast', [])
        ]
        available_art = _parse_artwork(movie, collection, self.urls, self.language)

        _info = {'set_tmdbid': movie['belongs_to_collection'].get('id')
            if movie['belongs_to_collection'] else None}

        return {'info': info, 'ratings': ratings, 'uniqueids': uniqueids, 'cast': cast,
            'available_art': available_art, '_info': _info}

def _parse_media_id(title):
    if title.startswith('tt') and title[2:].isdigit():
        return {'type': 'imdb', 'id':title} # IMDB ID works alone because it is clear
    title = title.lower()
    if title.startswith('tmdb/') and title[5:].isdigit(): # TMDB ID
        return {'type': 'tmdb', 'id':title[5:]}
    elif title.startswith('imdb/tt') and title[7:].isdigit(): # IMDB ID with prefix to match
        return {'type': 'imdb', 'id':title[5:]}
    return None

def _get_movie(mid, language=None, search=False):
    details = None if search else \
        'trailers,images,releases,casts,keywords' if language is not None else \
        'trailers'
    response = tmdbapi.get_movie(mid, language=language, append_to_response=details)
    theerror = response.get('error')
    if theerror:
        return 'error: {}'.format(theerror)
    else:
        return response

def _get_moviecollection(collection_id, language=None):
    if not collection_id:
        return None
    details = 'images'
    response = tmdbapi.get_collection(collection_id, language=language, append_to_response=details)
    theerror = response.get('error')
    if theerror:
        return 'error: {}'.format(theerror)
    else:
        return response

def _parse_artwork(movie, collection, urlbases, language):
    if language:
        # Image languages don't have regional variants
        language = language.split('-')[0]
    posters = []
    landscape = []
    fanart = []
    if 'images' in movie:
        posters = _get_images_with_fallback(movie['images']['posters'], urlbases, language)
        landscape = _get_images(movie['images']['backdrops'], urlbases, language)
        fanart = _get_images(movie['images']['backdrops'], urlbases, None)

    setposters = []
    setlandscape = []
    setfanart = []
    if collection and 'images' in collection:
        setposters = _get_images_with_fallback(collection['images']['posters'], urlbases, language)
        setlandscape = _get_images(collection['images']['backdrops'], urlbases, language)
        setfanart = _get_images(collection['images']['backdrops'], urlbases, None)

    return {'poster': posters, 'landscape': landscape, 'fanart': fanart,
        'set.poster': setposters, 'set.landscape': setlandscape, 'set.fanart': setfanart}

def _get_images_with_fallback(imagelist, urlbases, language, language_fallback='en'):
    images = _get_images(imagelist, urlbases, language)

    # Add backup images
    if language != language_fallback:
        images.extend(_get_images(imagelist, urlbases, language_fallback))

    # Add any images if nothing set so far
    if not images:
        images = _get_images(imagelist, urlbases)

    return images

def _get_images(imagelist, urlbases, language='_any'):
    result = []
    for img in imagelist:
        if language != '_any' and img['iso_639_1'] != language:
            continue
        result.append({
            'url': urlbases['original'] + img['file_path'],
            'preview': urlbases['preview'] + img['file_path'],
        })
    return result

def _get_date_numeric(datetime_):
    return (datetime_ - datetime(1970, 1, 1)).total_seconds()

def _load_base_urls(url_settings):
    urls = {}
    urls['original'] = url_settings.getSettingString('originalUrl')
    urls['preview'] = url_settings.getSettingString('previewUrl')
    last_updated = url_settings.getSettingString('lastUpdated')
    if not urls['original'] or not urls['preview'] or not last_updated or \
            float(last_updated) < _get_date_numeric(datetime.now() - timedelta(days=30)):
        conf = tmdbapi.get_configuration()
        if conf:
            urls['original'] = conf['images']['secure_base_url'] + 'original'
            urls['preview'] = conf['images']['secure_base_url'] + 'w780'
            url_settings.setSetting('originalUrl', urls['original'])
            url_settings.setSetting('previewUrl', urls['preview'])
            url_settings.setSetting('lastUpdated', str(_get_date_numeric(datetime.now())))
    return urls

def _parse_trailer(trailers, fallback):
    if trailers.get('youtube'):
        return 'plugin://plugin.video.youtube/?action=play_video&videoid='+trailers['youtube'][0]['source']
    if fallback.get('youtube'):
        return 'plugin://plugin.video.youtube/?action=play_video&videoid='+fallback['youtube'][0]['source']
    return None

def _get_names(items):
    return [item['name'] for item in items] if items else []

def _get_cast_members(casts, casttype, department, jobs):
    result = []
    if casttype in casts:
        for cast in casts[casttype]:
            if cast['department'] == department and cast['job'] in jobs and cast['name'] not in result:
                result.append(cast['name'])
    return result


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/tmdbapi.py
================================================
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2020, Team Kodi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
# pylint: disable=missing-docstring

"""Functions to interact with TMDb API."""

from . import api_utils
import xbmc
try:
    from typing import Optional, Text, Dict, List, Any  # pylint: disable=unused-import
    InfoType = Dict[Text, Any]  # pylint: disable=invalid-name
except ImportError:
    pass


HEADERS = (
    ('User-Agent', 'Kodi Movie scraper by Team Kodi'),
    ('Accept', 'application/json'),
)
api_utils.set_headers(dict(HEADERS))

TMDB_PARAMS = {'api_key': 'f090bb54758cabf231fb605d3e3e0468'}
BASE_URL = 'https://api.themoviedb.org/3/{}'
SEARCH_URL = BASE_URL.format('search/movie')
FIND_URL = BASE_URL.format('find/{}')
MOVIE_URL = BASE_URL.format('movie/{}')
COLLECTION_URL = BASE_URL.format('collection/{}')
CONFIG_URL = BASE_URL.format('configuration')


def search_movie(query, year=None, language=None):
    # type: (Text) -> List[InfoType]
    """
    Search for a movie

    :param title: movie title to search
    :param year: the year to search (optional)
    :param language: the language filter for TMDb (optional)
    :return: a list with found movies
    """
    xbmc.log('using title of %s to find movie' % query, xbmc.LOGDEBUG)
    theurl = SEARCH_URL
    params = _set_params(None, language)
    params['query'] = query
    if year is not None:
        params['year'] = str(year)
    return api_utils.load_info(theurl, params=params)


def find_movie_by_external_id(external_id, language=None):
    # type: (Text) -> List[InfoType]
    """
    Find movie based on external ID

    :param mid: external ID
    :param language: the language filter for TMDb (optional)
    :return: the movie or error
    """
    xbmc.log('using external id of %s to find movie' % external_id, xbmc.LOGDEBUG)
    theurl = FIND_URL.format(external_id)
    params = _set_params(None, language)
    params['external_source'] = 'imdb_id'
    return api_utils.load_info(theurl, params=params)



def get_movie(mid, language=None, append_to_response=None):
    # type: (Text) -> List[InfoType]
    """
    Get movie details

    :param mid: TMDb movie ID
    :param language: the language filter for TMDb (optional)
    :append_to_response: the additional data to get from TMDb (optional)
    :return: the movie or error
    """
    xbmc.log('using movie id of %s to get movie details' % mid, xbmc.LOGDEBUG)
    theurl = MOVIE_URL.format(mid)
    return api_utils.load_info(theurl, params=_set_params(append_to_response, language))


def get_collection(collection_id, language=None, append_to_response=None):
    # type: (Text) -> List[InfoType]
    """
    Get movie collection information

    :param collection_id: TMDb collection ID
    :param language: the language filter for TMDb (optional)
    :append_to_response: the additional data to get from TMDb (optional)
    :return: the movie or error
    """
    xbmc.log('using collection id of %s to get collection details' % collection_id, xbmc.LOGDEBUG)
    theurl = COLLECTION_URL.format(collection_id)
    return api_utils.load_info(theurl, params=_set_params(append_to_response, language))


def get_configuration():
    # type: (Text) -> List[InfoType]
    """
    Get configuration information

    :return: configuration details or error
    """
    xbmc.log('getting configuration details', xbmc.LOGDEBUG)
    return api_utils.load_info(CONFIG_URL, params=TMDB_PARAMS.copy())


def _set_params(append_to_response, language):
    params = TMDB_PARAMS.copy()
    img_lang = 'en,null'
    if language is not None:
        params['language'] = language
        img_lang = '%s,en,null' % language[0:2]
    if append_to_response is not None:
        params['append_to_response'] = append_to_response
        if 'images' in append_to_response:
            params['include_image_language'] = img_lang
    return params


================================================
FILE: metadata.douban.com.python/python/lib/tmdbscraper/traktratings.py
================================================
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2020, Team Kodi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
# pylint: disable=missing-docstring

"""Functions to interact with Trakt API."""

from __future__ import absolute_import, unicode_literals

from . import api_utils
from . import get_imdb_id
try:
    from typing import Optional, Text, Dict, List, Any  # pylint: disable=unused-import
    InfoType = Dict[Text, Any]  # pylint: disable=invalid-name
except ImportError:
    pass


HEADERS = (
    ('User-Agent', 'Kodi Movie scraper by Team Kodi'),
    ('Accept', 'application/json'),
    ('trakt-api-key', '5f2dc73b6b11c2ac212f5d8b4ec8f3dc4b727bb3f026cd254d89eda997fe64ae'),
    ('trakt-api-version', '2'),
    ('Content-Type', 'application/json'),
)
api_utils.set_headers(dict(HEADERS))

MOVIE_URL = 'https://api.trakt.tv/movies/{}'


def get_trakt_ratinginfo(uniqueids):
    imdb_id = get_imdb_id(uniqueids)
    result = {}
    url = MOVIE_URL.format(imdb_id)
    params = {'extended': 'full'}
    movie_info = api_utils.load_info(url, params=params, default={})
    if(movie_info):
        if 'votes' in movie_info and 'rating' in movie_info:
            result['ratings'] = {'trakt': {'votes': int(movie_info['votes']), 'rating': float(movie_info['rating'])}}
        elif 'rating' in movie_info:
            result['ratings'] = {'trakt': {'rating': float(movie_info['rating'])}}
    return result


================================================
FILE: metadata.douban.com.python/python/scraper.py
================================================
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import json
import sys
import xbmc
import xbmcaddon
import xbmcgui
import xbmcplugin

from lib.tmdbscraper.tmdb import TMDBMovieScraper
from lib.tmdbscraper.fanarttv import get_details as get_fanarttv_artwork
from lib.tmdbscraper.imdbratings import get_details as get_imdb_details
from lib.tmdbscraper.traktratings import get_trakt_ratinginfo
from scraper_datahelper import combine_scraped_details_info_and_ratings, \
    combine_scraped_details_available_artwork, find_uniqueids_in_text, get_params
from scraper_config import configure_scraped_details, PathSpecificSettings, \
    configure_tmdb_artwork, is_fanarttv_configured

from xbmcswift2 import Plugin
import requests
from bs4 import BeautifulSoup
import re
from requests.adapters import HTTPAdapter

ADDON_SETTINGS = xbmcaddon.Addon('metadata.douban.com.python')
ID = ADDON_SETTINGS.getAddonInfo('id')


def log(msg, level=xbmc.LOGDEBUG):
    xbmc.log(msg='[{addon}]: {msg}'.format(addon=ID, msg=msg), level=level)


headers = {
    # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    # 'Accept-Language': 'zh-CN,zh;q=0.9',
    # 'Cache-Control': 'max-age=0',
    # 'Connection': 'keep-alive',
    # 'Sec-Fetch-User': '?1',
    # 'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36'
}
plugin = Plugin()


# @plugin.cached(TTL=2)
def get_html(url, ua='pc', cookie='', mode='html', encode='utf-8'):
    #ConnectionError
    cloudflare = ADDON_SETTINGS.getSetting('cloudflareproxy')
    cloudflareurl = ADDON_SETTINGS.getSetting('cloudflareproxyurl')
    # dialog = xbmcgui.Dialog()
    # dialog.textviewer('错误提示', str(cloudflare))
    # dialog = xbmcgui.Dialog()
    # dialog.textviewer('错误提示', str(cloudflareurl))

    if cloudflare == 'true':
        if cloudflareurl[-1:] == '/':
            url = cloudflareurl + '-----' + url
        else:
            url = cloudflareurl + '/-----' + url
    else:
        dialog = xbmcgui.Dialog()
        dialog.notification('警告', '未设置代理Url可能使你的IP被豆瓣封禁',
                            xbmcgui.NOTIFICATION_WARNING, 5000, False)

    if cookie != '':
        cookie = eval(cookie)
    else:
        cookie = {}
    # UA相关
    head = headers
    # 超时重试3次
    # s0 = requests.Session()
    with requests.Session() as s0:
        s0.mount('http://', HTTPAdapter(max_retries=3))
        s0.mount('https://', HTTPAdapter(max_retries=3))

        # 获取网页源代码
        if mode == 'html':
            r = s0.get(url, headers=head, cookies=cookie, timeout=15)

            # 编码相关
            if encode == 'utf-8':
                r.encoding = 'utf-8'
            if encode == 'gbk':
                r.encoding = 'gbk'
            html = r.text

        # 用于获取302跳转网页的真实url
        if mode == 'url':
            head['Connection'] = 'close'
            r = s0.get(url, headers=head, timeout=5,
                       stream=True, cookies=cookie)
            html = r.url
        # dialog = xbmcgui.Dialog()
        # dialog.textviewer('错误提示', str(url))
        # dialog = xbmcgui.Dialog()
        # dialog.textviewer('错误提示', str(html.encode('utf-8')))
        return html

#获取视频真实url
def get_douban_videourl(url):
    r = get_html(url)
    soup = BeautifulSoup(r, 'html.parser')
    video = False
    counter = 1
    while soup.find('source', type="video/mp4") == False:
        r = get_html(url)
        soup = BeautifulSoup(r, 'html.parser')
        counter += 1
        if counter > 3:
            break
        if soup.find('source', type="video/mp4"):
            video = soup.find('source', type="video/mp4")['src']
            break
    return video


def get_douban_imglist(url):
    r = get_html(url)
    soup = BeautifulSoup(r, 'html.parser')
    ul = soup.find('ul', class_='poster-col3')
    li = ul.find_all('li')
    returnlist = []
    for index in range(len(li)):
        imgdict = {}
        img = li[index].find('img')['src']
        imgdict['preview'] = img
        img = re.sub('photo\/m', 'photo/r', img)
        imgdict['url'] = img
        returnlist.append(imgdict)
    return returnlist

# 构造仿tmdb的json
# [{
#         "poster_path": "https://1.jpg",
#         "title": "标题",
#         "release_date": "2019-06-19",
#         "id": 568160
#     }]


# def get_douban_search(title, year):
#     #r = get_html("https://search.douban.com/movie/subject_search?cat=1002&search_text=" + title)
#     r = get_html("https://www.douban.com/search?cat=1002&q=" + title)
#     #print(r.encode('utf-8'))
#     dialog = xbmcgui.Dialog()
#     dialog.textviewer('search', str(r.encode('utf-8')))
#     soup = BeautifulSoup(r, 'html.parser')
#     result = soup.find("div", class_="result-list")
#     resultlist = result.find_all('div', class_='result')
#     returnlist = []
#     for index in range(len(resultlist)):
#         returndict = {}
#         returndict['title'] = resultlist[index].find(
#             'div', class_="title").a.text
#         returndict['poster_path'] = resultlist[index].find(
#             'div', class_="pic").a.img['src']
#         returndict['release_date'] = re.search(
#             '(?<=/ )[\d]{4}$', resultlist[index].find('span', class_="subject-cast").text).group()
#         returndict['id'] = re.search(
#             '(?<=sid: )[\d]+', resultlist[index].find('div', class_="pic").a['onclick']).group()
#         returnlist.append(returndict)
#     return returnlist
def get_douban_search(title, year):
    r = get_html('https://movie.douban.com/j/subject_suggest?q=' + title)
    j = json.loads(r)
    returnlist = []
    for index in range(len(j)):
        returndict = {}
        returndict['title'] = j[index]['sub_title']
        returndict['poster_path'] = j[index]['img'].replace(
            's_ratio_poster', 'r')
        returndict['release_date'] = j[index]['year'] + '-01-01'
        returndict['id'] = j[index]['id']
        returnlist.append(returndict)

    return returnlist

# 用douban的数据,构造仿tmdb的json


def get_douban_details(input_uniqueids):
    doubanjson = {
        "info": {
            "mpaa": "PG-13",
            "studio": ["豆瓣电影"],
            "tag": [],
            "trailer":""
        },
        "ratings": {
            "themoviedb": {}
        },
        "available_art": {
            "set.landscape": [],
            "set.fanart": [],
            "set.poster": [],
            "fanart": [],
            "poster": [],
            "landscape": []
        },
        "uniqueids": {},
        "cast": [],
        "_info": {
            "set_tmdbid": None
        }}
    #传入input_uniqueids = {'tmdb':'123456'}
    doubanid = int(input_uniqueids['tmdb'])
    doubanjson['uniqueids']['tmdb'] = doubanid
    doubanurl = 'http://movie.douban.com/subject/' + str(doubanid) + '/'
    r = get_html(doubanurl)
    print(r.encode('utf-8'))
    soup = BeautifulSoup(r, 'html.parser')

    # 国家
    countrys = []
    info = soup.find('div',id='info')
    country = re.search(r'(?<=制片国家/地区:</span>).*?(?=<br/>)',str(info)).group()
    # country = '日本'
    if re.search('/', country):
        country = country.split('/')
        for i in range(len(country)):
            countrys.append(country[i].strip())
    else:
        countrys.append(country.strip())
    doubanjson['info']['country'] = countrys

    # 标题&年
    doubanjson['info']['title'] = soup.find(
        'span', property="v:itemreviewed").text
    #year = soup.find('span',class_="year").text.replace('(','').replace(')','')

    # 豆瓣评分&人数
    doubanjson['ratings']['themoviedb']['rating'] = float(
        soup.find('strong', class_="ll rating_num").text)
    doubanjson['ratings']['themoviedb']['votes'] = int(
        soup.find('span', property="v:votes").text)

    # 简介
    doubanjson['info']['plot'] = soup.find(
        'span', property="v:summary").text.strip()

    # 预告片
    if get_douban_videourl(soup.find('a', title="预告片")['href']):
        trailer = get_douban_videourl(soup.find('a', title="预告片")['href']) + '|referer=' + doubanurl
        doubanjson['info']['trailer'] = trailer

    # 类型
    genre = soup.find_all('span', property="v:genre")
    genres = []
    for i in range(len(genre)):
        genres.append(genre[i].text)
    doubanjson['info']['genre'] = genres

    # 时长
    doubanjson['info']['duration'] = int(
        soup.find('span', property="v:runtime")['content'])*60

    # 日期
    doubanjson['info']['premiered'] = re.search(
        '[\d]{4}-[\d]{2}-[\d]{2}', soup.find('span', property="v:initialReleaseDate")['content']).group()

    

    # 标签
    taglist = []
    tag = soup.find('div', class_='tags-body')
    tags = tag.find_all('a')
    for i in range(len(tags)):
        taglist.append(tags[i].text)
    doubanjson['info']['tag'] = taglist

    # 剧照
    doubanjson['available_art']['fanart'] = get_douban_imglist('https://movie.douban.com/subject/' + str(doubanid) + '/photos?type=S')

    # 海报
    doubanjson['available_art']['poster'] = get_douban_imglist('https://movie.douban.com/subject/' + str(doubanid) + '/photos?type=R')

    # 导演&编剧&演员
    r = get_html("https://movie.douban.com/subject/" +
                 str(doubanid) + "/celebrities")
    soup = BeautifulSoup(r, 'html.parser')

    director = []
    credit = []
    cast = []
    celebrities = soup.find('div', id='celebrities').find_all(
        'div', class_='list-wrapper')
    for index in range(len(celebrities)):
        if celebrities[index].h2.text == u'导演 Director':
            li = celebrities[index].find_all('li')
            for i in range(len(li)):
                director.append(li[i].a['title'])
        if celebrities[index].h2.text == u'编剧 Writer':
            li = celebrities[index].find_all('li')
            for i in range(len(li)):
                credit.append(li[i].a['title'])
        if celebrities[index].h2.text == u'演员 Cast':
            li = celebrities[index].find_all('li')
            for i in range(len(li)):
                castdict = {}
                castdict['order'] = i
                castdict['role'] = li[i].find('span', class_='role')['title']
                castdict['name'] = li[i].a['title']
                castdict['thumbnail'] = li[i].a.div['style'].replace(
                    'background-image: url(', '').replace(')', '').replace('s_ratio_celebrity', 'r')
                cast.append(castdict)
    doubanjson['info']['director'] = director
    doubanjson['info']['credits'] = credit
    doubanjson['cast'] = cast
    return doubanjson


def get_tmdb_scraper(settings):
    language = settings.getSettingString('language')
    certcountry = settings.getSettingString('tmdbcertcountry')
    # dialog = xbmcgui.Dialog()
    # #dialog.notification('提示', '已关闭', xbmcgui.NOTIFICATION_INFO, 5000)
    # dialog.textviewer('提示', str(TMDBMovieScraper(ADDON_SETTINGS, language, certcountry)))
    return TMDBMovieScraper(ADDON_SETTINGS, language, certcountry)


def search_for_movie(title, year, handle, settings):
    # 刮削&搜索
    log("Find movie with title '{title}' from year '{year}'".format(
        title=title, year=year), xbmc.LOGINFO)
    title = _strip_trailing_article(title)
    # 输出json结果
    search_results = get_douban_search(title, year)
    #search_results = get_tmdb_scraper(settings).search(title, year)
    #dialog = xbmcgui.Dialog()
    #dialog.textviewer('提示', str(get_tmdb_scraper(settings).search(title, year)))

    if not search_results:
        return
    # if 'error' in search_results:
    #     header = "The Movie Database Python error searching with web service TMDB"
    #     xbmcgui.Dialog().notification(header, search_results['error'], xbmcgui.NOTIFICATION_WARNING)
    #     log(header + ': ' + search_results['error'], xbmc.LOGWARNING)
    #     return

    for movie in search_results:
        listitem = _searchresult_to_listitem(movie)
        uniqueids = {'tmdb': str(movie['id'])}
        xbmcplugin.addDirectoryItem(handle=handle, url=build_lookup_string(uniqueids),
                                    listitem=listitem, isFolder=True)


_articles = [
    prefix + article for prefix in (', ', ' ') for article in ("the", "a", "an")]


def _strip_trailing_article(title):
    title = title.lower()
    for article in _articles:
        if title.endswith(article):
            return title[:-len(article)]
    return title


def _searchresult_to_listitem(movie):
    # 显示搜索结果  天气之子(2019)
    movie_info = {'title': movie['title']}
    movie_label = movie['title']

    movie_year = movie['release_date'].split(
        '-')[0] if movie.get('release_date') else None
    if movie_year:
        movie_label += ' ({})'.format(movie_year)
        movie_info['year'] = movie_year

    listitem = xbmcgui.ListItem(movie_label, offscreen=True)

    listitem.setInfo('video', movie_info)
    if movie['poster_path']:
        listitem.setArt({'thumb': movie['poster_path']})
    # dialog = xbmcgui.Dialog()
    # dialog.textviewer('提示111', str(movie_info))
    return listitem


# Low limit because a big list of artwork can cause trouble in some cases
# (a column can be too large for the MySQL integration),
# and how useful is a big list anyway? Not exactly rhetorical, this is an experiment.
IMAGE_LIMIT = 10


def add_artworks(listitem, artworks):
    for arttype, artlist in artworks.items():
        if arttype == 'fanart':
            continue
        for image in artlist[:IMAGE_LIMIT]:
            listitem.addAvailableArtwork(image['url'], arttype)

    fanart_to_set = [{'image': image['url'], 'preview': image['preview']}
                     for image in artworks['fanart'][:IMAGE_LIMIT]]
    listitem.setAvailableFanart(fanart_to_set)


def get_details(input_uniqueids, handle, settings):
    # 解析详细信息
    if not input_uniqueids:
        return False

    #details = get_tmdb_scraper(settings).get_details(input_uniqueids)
    #传入input_uniqueids = {'tmdb':'123456'}
    details = get_douban_details(input_uniqueids)
    
    # dialog = xbmcgui.Dialog()
    # dialog.textviewer('details', str(input_uniqueids))
    if not details:
        return False
    # if 'error' in details:
    #     header = "The Movie Database Python error with web service TMDB"
    #     xbmcgui.Dialog().notification(header, details['error'], xbmcgui.NOTIFICATION_WARNING)
    #     log(header + ': ' + details['error'], xbmc.LOGWARNING)
    #     return False

    # details = configure_tmdb_artwork(details, settings)

    if settings.getSettingString('RatingS') == 'IMDb' or settings.getSettingBool('imdbanyway'):
        imdbinfo = get_imdb_details(details['uniqueids'])
        if 'error' in imdbinfo:
            header = "The Movie Database Python error with website IMDB"
            log(header + ': ' + imdbinfo['error'], xbmc.LOGWARNING)
        else:
            details = combine_scraped_details_info_and_ratings(
                details, imdbinfo)

    if settings.getSettingString('RatingS') == 'Trakt' or settings.getSettingBool('traktanyway'):
        traktinfo = get_trakt_ratinginfo(details['uniqueids'])
        details = combine_scraped_details_info_and_ratings(details, traktinfo)

    if is_fanarttv_configured(settings):
        fanarttv_info = get_fanarttv_artwork(details['uniqueids'],
                                             settings.getSettingString(
                                                 'fanarttv_clientkey'),
                                             settings.getSettingString(
                                                 'fanarttv_language'),
                                             details['_info']['set_tmdbid'])
        details = combine_scraped_details_available_artwork(
            details, fanarttv_info)

    details = configure_scraped_details(details, settings)

    listitem = xbmcgui.ListItem(details['info']['title'], offscreen=True)
    listitem.setInfo('video', details['info'])
    listitem.setCast(details['cast'])
    listitem.setUniqueIDs(details['uniqueids'], 'tmdb')
    add_artworks(listitem, details['available_art'])

    for rating_type, value in details['ratings'].items():
        if 'votes' in value:
            listitem.setRating(
                rating_type, value['rating'], value['votes'], value['default'])
        else:
            listitem.setRating(
                rating_type, value['rating'], defaultt=value['default'])

    xbmcplugin.setResolvedUrl(handle=handle, succeeded=True, listitem=listitem)
    return True


def find_uniqueids_in_nfo(nfo, handle):
    uniqueids = find_uniqueids_in_text(nfo)
    if uniqueids:
        listitem = xbmcgui.ListItem(offscreen=True)
        xbmcplugin.addDirectoryItem(
            handle=handle, url=build_lookup_string(uniqueids), listitem=listitem, isFolder=True)


def build_lookup_string(uniqueids):
    return json.dumps(uniqueids)


def parse_lookup_string(uniqueids):
    try:
        return json.loads(uniqueids)
    except ValueError:
        log("Can't parse this lookup string, is it from another add-on?\n" +
            uniqueids, xbmc.LOGWARNING)
        return None


def run():
    params = get_params(sys.argv[1:])
    enddir = True
    if 'action' in params:
        settings = ADDON_SETTINGS if not params.get('pathSettings') else \
            PathSpecificSettings(json.loads(
                params['pathSettings']), lambda msg: log(msg, xbmc.LOGWARNING))
        action = params["action"]
        if action == 'find' and 'title' in params:
            search_for_movie(params["title"], params.get(
                "year"), params['handle'], settings)
        elif action == 'getdetails' and 'url' in params:
            enddir = not get_details(parse_lookup_string(
                params["url"]), params['handle'], settings)
        elif action == 'NfoUrl' and 'nfo' in params:
            find_uniqueids_in_nfo(params["nfo"], params['handle'])
        else:
            log("unhandled action: " + action, xbmc.LOGWARNING)
    else:
        log("No action in 'params' to act on", xbmc.LOGWARNING)
    if enddir:
        xbmcplugin.endOfDirectory(params['handle'])


if __name__ == '__main__':
    run()


================================================
FILE: metadata.douban.com.python/python/scraper_config.py
================================================
def configure_scraped_details(details, settings):
    details = _configure_rating_prefix(details, settings)
    details = _configure_keeporiginaltitle(details, settings)
    details = _configure_trailer(details, settings)
    details = _configure_multiple_studios(details, settings)
    details = _configure_default_rating(details, settings)
    details = _configure_tags(details, settings)
    return details

def configure_tmdb_artwork(details, settings):
    if 'available_art' not in details:
        return details

    art = details['available_art']
    fanart_enabled = settings.getSettingBool('fanart')
    if not fanart_enabled:
        if 'fanart' in art:
            del art['fanart']
        if 'set.fanart' in art:
            del art['set.fanart']
    if not settings.getSettingBool('landscape'):
        if 'landscape' in art:
            if fanart_enabled:
                art['fanart'] = art.get('fanart', []) + art['landscape']
            del art['landscape']
        if 'set.landscape' in art:
            if fanart_enabled:
                art['set.fanart'] = art.get('set.fanart', []) + art['set.landscape']
            del art['set.landscape']

    return details

def is_fanarttv_configured(settings):
    return settings.getSettingBool('enable_fanarttv_artwork')

def _configure_rating_prefix(details, settings):
    if details['info'].get('mpaa'):
        details['info']['mpaa'] = settings.getSettingString('certprefix') + details['info']['mpaa']
    return details

def _configure_keeporiginaltitle(details, settings):
    if settings.getSettingBool('keeporiginaltitle'):
        details['info']['title'] = details['info']['originaltitle']
    return details

def _configure_trailer(details, settings):
    # if details['info'].get('trailer') and not settings.getSettingBool('trailer'):
    #     del details['info']['trailer']
    return details

def _configure_multiple_studios(details, settings):
    if not settings.getSettingBool('multiple_studios'):
        details['info']['studio'] = details['info']['studio'][:1]
    return details

def _configure_default_rating(details, settings):
    imdb_default = bool(details['ratings'].get('imdb')) and settings.getSettingString('RatingS') == 'IMDb'
    trakt_default = bool(details['ratings'].get('trakt')) and settings.getSettingString('RatingS') == 'Trakt'
    default_rating = 'themoviedb'
    if imdb_default:
        default_rating = 'imdb'
    elif trakt_default:
        default_rating = 'trakt'
    if default_rating not in details['ratings']:
        default_rating = list(details['ratings'].keys())[0] if details['ratings'] else None
    for rating_type in details['ratings'].keys():
        details['ratings'][rating_type]['default'] = rating_type == default_rating
    return details

def _configure_tags(details, settings):
    # if not settings.getSettingBool('add_tags'):
    #     del details['info']['tag']
    return details

# pylint: disable=invalid-name
try:
    basestring
except NameError: # py2 / py3
    basestring = str

#pylint: disable=redefined-builtin
class PathSpecificSettings(object):
    # read-only shim for typed `xbmcaddon.Addon().getSetting*` methods
    def __init__(self, settings_dict, log_fn):
        self.data = settings_dict
        self.log = log_fn

    def getSettingBool(self, id):
        return self._inner_get_setting(id, bool, False)

    def getSettingInt(self, id):
        return self._inner_get_setting(id, int, 0)

    def getSettingNumber(self, id):
        return self._inner_get_setting(id, float, 0.0)

    def getSettingString(self, id):
        return self._inner_get_setting(id, basestring, '')

    def _inner_get_setting(self, setting_id, setting_type, default):
        value = self.data.get(setting_id)
        if isinstance(value, setting_type):
            return value
        self._log_bad_value(value, setting_id)
        return default

    def _log_bad_value(self, value, setting_id):
        if value is None:
            self.log("requested setting ({0}) was not found.".format(setting_id))
        else:
            self.log('failed to load value "{0}" for setting {1}'.format(value, setting_id))


================================================
FILE: metadata.douban.com.python/python/scraper_datahelper.py
================================================
import re
try:
    from urlparse import parse_qsl
except ImportError: # py2 / py3
    from urllib.parse import parse_qsl

# get addon params from the plugin path querystring
def get_params(argv):
    result = {'handle': int(argv[0])}
    if len(argv) < 2 or not argv[1]:
        return result

    result.update(parse_qsl(argv[1].lstrip('?')))
    return result

def combine_scraped_details_info_and_ratings(original_details, additional_details):
    def update_or_set(details, key, value):
        if key in details:
            details[key].update(value)
        else:
            details[key] = value

    if additional_details:
        if additional_details.get('info'):
            update_or_set(original_details, 'info', additional_details['info'])
        if additional_details.get('ratings'):
            update_or_set(original_details, 'ratings', additional_details['ratings'])
    return original_details

def combine_scraped_details_available_artwork(original_details, additional_details):
    if additional_details and additional_details.get('available_art'):
        available_art = additional_details['available_art']
        if not original_details.get('available_art'):
            original_details['available_art'] = available_art
        else:
            for arttype, artlist in available_art.items():
                original_details['available_art'][arttype] = \
                    artlist + original_details['available_art'].get(arttype, [])

    return original_details

def find_uniqueids_in_text(input_text):
    result = {}
    res = re.search(r'(themoviedb.org/movie/)([0-9]+)', input_text)
    if (res):
        result['tmdb'] = res.group(2)
    res = re.search(r'imdb....?/title/tt([0-9]+)', input_text)
    if (res):
        result['imdb'] = 'tt' + res.group(1)
    else:
        res = re.search(r'imdb....?/Title\?t{0,2}([0-9]+)', input_text)
        if (res):
            result['imdb'] = 'tt' + res.group(1)
    return result


================================================
FILE: metadata.douban.com.python/resources/language/Chinese (Simple)/strings.po
================================================
msgid ""
msgstr ""

#Chinese Simplified

msgctxt "#33001"
msgid "proxy"
msgstr "代理设置"

msgctxt "#33002"
msgid "cloudflareproxy"
msgstr "启用豆瓣代理(cloudflare worker)"

msgctxt "#33003"
msgid "cloudflareproxyurl"
msgstr "代理url"


================================================
FILE: metadata.douban.com.python/resources/settings.xml
================================================
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
	<category label="33001" id="proxy">
		<setting label="33002" type="bool" id="cloudflareproxy" default="true"/>
		<setting label="33003" type="text" id="cloudflareproxyurl" default="https://proud-band-6b60.zhengfan2014.workers.dev/" />
	</category>
</settings>


================================================
FILE: plugin.audio.jsososo/addon.py
================================================
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from xbmcswift2 import Plugin, xbmcgui, xbmc, xbmcaddon, xbmcplugin
#from xbmcswift2 import Actions
import requests
from bs4 import BeautifulSoup
import xbmcgui
import base64
import json
import urllib2
import sys
import HTMLParser
import re
import time

def unix_to_data(uptime,format='data'):
    if len(str(uptime)) > 10:
        uptime = str(uptime)[:-(len(str(uptime))-10)]
    uptime = float(uptime)
    time_local = time.localtime(uptime)
    if format == 'data' or format == 'zhdata' or format == 'datatime' or format == 'zhdatatime' or format == 'time' or format == 'zhtime':
        if format == 'data':
            uptime = time.strftime('%Y-%m-%d',time_local)
        if format == 'zhdata':
            uptime = time.strftime('%Y年%m月%d日',time_local)
        if format == 'datatime':
            uptime = time.strftime('%Y-%m-%d %H:%M:%S',time_local)
        if format == 'zhdatatime':
            uptime = time.strftime('%Y年%m月%d日 %H时%M分%S秒',time_local)
        if format == 'time':
            uptime = time.strftime('%H:%M:%S',time_local)
        if format == 'zhtime':
            uptime = time.strftime('%H时%M分%S秒',time_local)
    else:
        uptime = time.strftime(format,time_local)
    return uptime

#超过10000换算
def zh(num):
    if int(num) >= 100000000:
        p = round(float(num)/float(100000000), 1)
        p = str(p) + '亿'
    else:
        if int(num) >= 10000:
            p = round(float(num)/float(10000), 1)
            p = str(p) + '万'
        else:
            p = str(num)
    return p

def get_real_url(url):
    rs = requests.get(url,headers=headers,timeout=2)
    return rs.url

def unescape(string):
    string = urllib2.unquote(string).decode('utf8')
    quoted = HTMLParser.HTMLParser().unescape(string).encode('utf-8')
    #转成中文
    return re.sub(r'%u([a-fA-F0-9]{4}|[a-fA-F0-9]{2})', lambda m: unichr(int(m.group(1), 16)), quoted)


plugin = Plugin()


headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36'}
cache = plugin.get_storage('cache')
his = plugin.get_storage('his')

#初始化api
# if 'myqq' not in cache:
#     cache['myqq'] = ''
# if 'my163' not in cache:
#     cache['my163'] = ''
# if 'my163num' not in cache:
#     cache['my163num'] = ''
# if 'myqqnum' not in cache:
#     cache['myqqnum'] = ''
# xbmcplugin.setContent(int(sys.argv[1]), 'musicvideos')

netease_api = xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicapiurl')
qqmusic_api = xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusicapiurl')
migu_api = xbmcplugin.getSetting(int(sys.argv[1]), 'miguapiurl')


@plugin.cached(TTL=1)
def get_html(url,cookie=''):
    if cookie != '':
        h = headers
        h['cookie'] = cookie
        r = requests.get(url,headers=h)
    else:
        r = requests.get(url,headers=headers)
    return r.text

########################################### 为你推荐歌单api ###########################################
def one63weinituijian():
    gedans = []
    r = get_html(netease_api + '/recommend/resource','MUSIC_U=' + xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicu'))
    j = json.loads(r)
    if j['code'] == 200:
        glist = j['recommend']
        for index in range(len(glist)):
            desc = ''
            if glist[index]['copywriter']:
                desc += glist[index]['copywriter'].encode('utf-8')
            gd ={}
            gd['name'] = glist[index]['name']
            gd['thumb'] = glist[index]['picUrl']
            gd['url'] = 'https://music.163.com/#/playlist?id=' + str(glist[index]['id'])
            gd['info'] = {'plot':zh(glist[index]['playcount']) + ' 播放 · ' + zh(glist[index]['trackCount']) + ' 首歌\n\n' + desc}
            gd['info']['cast'] = [(glist[index]['creator']['nickname'],unix_to_data(glist[index]['createTime']) + u'创建')]
            gedans.append(gd)
        return gedans
    else:
        if j['code'] == 301:
            dialog = xbmcgui.Dialog()
            dialog.notification('请求失败','请尝试更换MUSIC_U', xbmcgui.NOTIFICATION_INFO, 5000)

def qqweinituijian():
    gedans = []
    r = get_html(qqmusic_api + '/recommend/playlist/u')
    j = json.loads(r)
    glist = j['data']['list']
    for index in range(len(glist)):
        gd ={}
        gd['name'] = glist[index]['title']
        gd['thumb'] = glist[index]['cover']
        gd['url'] = 'https://y.qq.com/n/yqq/playlist/' + str(glist[index]['content_id']) + '.html'
        gd['info'] = {'plot':zh(glist[index]['listen_num']) + ' 播放量'}
        gd['info']['cast']= [glist[index]['username']]
        gedans.append(gd)
    return gedans
########################################### 日推api ###########################################
def one63ritui():
    gedans = []
    r = get_html(netease_api + '/recommend/songs','MUSIC_U='+xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicu'))
    j = json.loads(r)
    if j['code'] == 200:
        gedans = []
        glist = j['recommend']
        # songs = ''
        # for index in range(len(glist)):
        #     if index == 0:
        #         songs += str(glist[index]['id'])
        #     else:
        #         songs += ',' + str(glist[index]['id'])
        # #mp3 url
        # r2 = get_html(netease_api + '/song/url?id=' + songs)
        # j2 = json.loads(r2)
        # mp3urls = j2['data']
        for index in range(len(glist)):
            gd ={}
            gd['name'] = glist[index]['name']
            gd['thumb'] = glist[index]['album']['picUrl']
            # gdurl = ''
            # for i in range(len(mp3urls)):
            #     if int(mp3urls[i]['id']) == int(glist[index]['id']):
            #         gdurl = mp3urls[i]['url']
            # if gdurl == '':
            #     gd['name'] += ' - [无版权]'
            if xbmcplugin.getSetting(int(sys.argv[1]), 'httpswitch') == 'true':
                gdurl =  'http'
            else:
                gdurl = 'https'
            gdurl += '://music.163.com/song/media/outer/url?id='+str(glist[index]['id'])+'.mp3'
            gd['url'] = gdurl
            gd['info'] = {'title':glist[index]['name'],'album':glist[index]['album']['name'],'artist':glist[index]['artists'][0]['name'],'mediatype':'song'}
            #gd['url'] = j2['data'][0]['url']
            gedans.append(gd)
        return gedans
    else:
        if j['code'] == 301:
            dialog = xbmcgui.Dialog()
            dialog.notification('请求失败','请尝试更换网易云音乐的 MUSIC_U', xbmcgui.NOTIFICATION_INFO, 5000)

def qqritui():
    gedans = []
    r = get_html(qqmusic_api + '/recommend/daily',xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookie'))
    j = json.loads(r)
    if j['result'] == 100:
        glist = j['data']['songlist']
        songs= ''
        for index in range(len(glist)):
            if index == 0:
                songs += glist[index]['songmid']
            else:
                songs += ',' + glist[index]['songmid']
        r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
        j1 = json.loads(r1)
        mp3urls = j1['data']
        for index in range(len(glist)):
            if glist[index]['songmid'] in mp3urls:
                gd ={}
                gd['name'] = glist[index]['songname']
                gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['albummid'] + '.jpg'
                gd['url'] = mp3urls[glist[index]['songmid']]
                gd['info'] = {'title':glist[index]['songname'],'album':glist[index]['albumname'],'artist':glist[index]['singer'][0]['name'],'mediatype':'song'}
                gedans.append(gd)
        return gedans
    else:
        if j['result'] == 301:
            dialog = xbmcgui.Dialog()
            dialog.notification('请求失败','请尝试更换QQ音乐的 cookie', xbmcgui.NOTIFICATION_INFO, 5000)    

########################################### 我的歌单api ###########################################
def one63gedan():
    gedans = []
    r = get_html(netease_api + '/user/playlist?uid=' + str(xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicuid')))
    j = json.loads(r)
    glist = j['playlist']
    for index in range(len(glist)):
        desc = ''
        if glist[index]['description']:
            desc += glist[index]['description'].encode('utf-8')
        gd ={}
        gd['name'] = glist[index]['name']
        gd['thumb'] = glist[index]['coverImgUrl']
        gd['url'] = 'https://music.163.com/#/playlist?id=' + str(glist[index]['id'])
        gd['info'] = {'plot':zh(glist[index]['playCount']) + ' 播放 · ' + zh(glist[index]['trackCount']) + ' 首歌\n\n' + desc}
        gd['info']['cast'] = [(glist[index]['creator']['nickname'],unix_to_data(glist[index]['createTime']) + u'创建')]
        gedans.append(gd)
    return gedans

def qqgedan():
    gedans = []
    r = get_html(qqmusic_api + '/user/songlist?id=' + str(xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusicid')))
    j = json.loads(r)
    glist = j['data']['list']
    for index in range(len(glist)):
        if int(glist[index]['tid']) > 0:
            gd ={}
            gd['name'] = glist[index]['diss_name']
            gd['thumb'] = glist[index]['diss_cover']
            gd['url'] = 'https://y.qq.com/n/yqq/playlist/' + str(glist[index]['tid']) + '.html'
            gd['info'] = {'plot':zh(glist[index]['listen_num']) + ' 播放 · ' + zh(glist[index]['song_cnt']) + ' 首歌'}
            gd['info']['cast'] = [j['data']['creator']['hostname']]
            gedans.append(gd)
    return gedans
########################################### 推荐歌单api ###########################################

def one63tuijiangedan():
    gedans = []
    r = get_html(netease_api + '/personalized')
    j = json.loads(r)
    glist = j['result']
    for index in range(len(glist)):
        gd ={}
        gd['name'] = glist[index]['name']
        gd['thumb'] = glist[index]['picUrl']
        gd['url'] = 'https://music.163.com/#/playlist?id=' + str(glist[index]['id'])
        gd['info'] = {'plot':zh(glist[index]['playCount']) + ' 播放 · ' + zh(glist[index]['trackCount']) + ' 首歌\n\n' + glist[index]['copywriter'].encode('utf-8')}
        gd['info']['cast'] = ['不知道是谁']
        gedans.append(gd)
    return gedans

def qqtuijiangedan():
    gedans = []
    r = get_html(qqmusic_api + '/recommend/playlist/')
    j = json.loads(r)
    glist = j['data']['list']
    for index in range(len(glist)):
        gd ={}
        gd['name'] = glist[index]['title']
        gd['thumb'] = glist[index]['cover_url_big']
        gd['url'] = 'https://y.qq.com/n/yqq/playlist/' + str(glist[index]['tid']) + '.html'
        gd['info'] = {'plot':zh(glist[index]['access_num']) + ' 播放量'}
        gd['info']['cast']= [glist[index]['creator_info']['nick']]
        gedans.append(gd)
    return gedans

########################################### 歌单详细信息api ###########################################
def one63playlist(id):
    gedans = []
    r = get_html(netease_api + '/playlist/detail?id=' + str(id))
    j = json.loads(r)
    glist = j['playlist']['trackIds']
    songs = ''
    for index in range(len(glist)):
        if index == 0:
            songs += str(glist[index]['id'])
        else:
            songs += ',' + str(glist[index]['id'])
    #mp3详情
    r1 = get_html(netease_api + '/song/detail?ids=' + songs)
    j1 = json.loads(r1)
    mp3detail = j1['songs']
    # #mp3 url
    # r2 = get_html(netease_api + '/song/url?id=' + songs)
    # j2 = json.loads(r2)
    # mp3urls = j2['data']
    # pDialog = xbmcgui.DialogProgress()
    # pDialog.create('网易云音乐', '努力从母猪厂的土豆服务器偷mp3中...(0%)')
    for index in range(len(mp3detail)):
        # pDialog.update(int(100*(float(index)/float(len(mp3detail)))), '努力从母猪厂的土豆服务器偷mp3中...('+str(int(100*(float(index)/float(len(mp3detail)))))+'%)')
        # #r2 = get_html(netease_api + '/song/url?id=' + str(mp3detail[index]['id']))
        # #j2 = json.loads(r2)
        gd ={}
        gd['name'] = mp3detail[index]['name']
        gd['thumb'] = mp3detail[index]['al']['picUrl']
        # gdurl = ''
        # for i in range(len(mp3urls)):
        #     if int(mp3urls[i]['id']) == int(mp3detail[index]['id']):
        #         gdurl = mp3urls[i]['url']
        # if gdurl == '':
        #     gd['name'] += ' - [无版权]'
        # gd['url'] = gdurl
        if xbmcplugin.getSetting(int(sys.argv[1]), 'httpswitch') == 'true':
            gd['url'] = 'http'
        else:
            gd['url'] = 'https'
        gd['url'] += '://music.163.com/song/media/outer/url?id=' + str(mp3detail[index]['id']) + '.mp3'
        gd['info'] = {'title':mp3detail[index]['name'],'album':mp3detail[index]['al']['name'],'artist':mp3detail[index]['ar'][0]['name'],'mediatype':'song'}
        #gd['url'] = j2['data'][0]['url']
        gedans.append(gd)
    return gedans

def qqplaylist(id):
    gedans = []
    r = get_html(qqmusic_api + '/songlist?id=' + str(id))
    j = json.loads(r)
    glist = j['data']['songlist']
    songs= ''
    for index in range(len(glist)):
        if index == 0:
            songs += glist[index]['songmid']
        else:
            songs += ',' + glist[index]['songmid']
    r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
    j1 = json.loads(r1)
    mp3urls = j1['data']
    
    for index in range(len(glist)):
        
        if glist[index]['songmid'] in mp3urls:
            gd ={}
            gd['name'] = glist[index]['songname']
            gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['albummid'] + '.jpg'
            gd['url'] = mp3urls[glist[index]['songmid']]
            gd['info'] = {'title':glist[index]['songname'],'album':glist[index]['albumname'],'artist':glist[index]['singer'][0]['name'],'mediatype':'song'}
            gedans.append(gd)
    return gedans

########################################### 专辑详细信息api ###########################################
def one63album(id):
    gedans = []
    r = get_html(netease_api + '/playlist/detail?id=' + str(id))
    j = json.loads(r)
    glist = j['playlist']['trackIds']
    songs = ''
    for index in range(len(glist)):
        if index == 0:
            songs += str(glist[index]['id'])
        else:
            songs += ',' + str(glist[index]['id'])
    #mp3详情
    r1 = get_html(netease_api + '/song/detail?ids=' + songs)
    j1 = json.loads(r1)
    mp3detail = j1['songs']
    # #mp3 url
    # r2 = get_html(netease_api + '/song/url?id=' + songs)
    # j2 = json.loads(r2)
    # mp3url = j2['data']
    for index in range(len(mp3detail)):
        gd ={}
        gd['name'] = mp3detail[index]['name']
        gd['thumb'] = mp3detail[index]['al']['picUrl']
        # gd['url'] = mp3url[index]['url']
        if xbmcplugin.getSetting(int(sys.argv[1]), 'httpswitch') == 'true':
            gd['url'] = 'http'
        else:
            gd['url'] = 'https'
        gd['url'] += '://music.163.com/song/media/outer/url?id=' + str(mp3detail[index]['id']) + '.mp3'
        gedans.append(gd)
    return gedans

def qqalbum(id):
    gedans = []
    r = get_html(qqmusic_api + '/album/songs?albummid=' + str(id))
    j = json.loads(r)
    glist = j['data']['list']
    songs= ''
    for index in range(len(glist)):
        if index == 0:
            songs += glist[index]['mid']
        else:
            songs += ',' + glist[index]['mid']
    r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
    j1 = json.loads(r1)
    mp3urls = j1['data']
    
    for index in range(len(glist)):
        
        if glist[index]['mid'] in mp3urls:
            gd ={}
            gd['name'] = glist[index]['name']
            gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['album']['mid'] + '.jpg'
            gd['url'] = mp3urls[glist[index]['mid']]
            gedans.append(gd)
    return gedans

########################################### 歌手热门歌曲api ###########################################
def one63singer(id):
    gedans = []
    r = get_html(netease_api + '/artists?id=' + str(id))
    j = json.loads(r)
    glist = j['hotSongs']
    for index in range(len(glist)):
        gd ={}
        gd['name'] = glist[index]['name']
        gd['thumb'] = glist[index]['al']['picUrl']
        #mp3 url
        r2 = get_html(netease_api + '/song/url?id=' + str(glist[index]['id']))
        j2 = json.loads(r2)
        gd['url'] = j2['data'][0]['url']
        gedans.append(gd)
    return gedans

def qqsinger(id):
    gedans = []
    r = get_html(qqmusic_api + '/singer/songs?num=50&singermid=' + str(id))
    j = json.loads(r)
    glist = j['data']['list']
    songs= ''
    for index in range(len(glist)):
        if index == 0:
            songs += glist[index]['mid']
        else:
            songs += ',' + glist[index]['mid']
    r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
    j1 = json.loads(r1)
    mp3urls = j1['data']
    
    for index in range(len(glist)):
        
        if glist[index]['mid'] in mp3urls:
            gd ={}
            gd['name'] = glist[index]['name']
            gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['album']['mid'] + '.jpg'
            gd['url'] = mp3urls[glist[index]['mid']]
            gedans.append(gd)
    return gedans
########################################### 排行 ###########################################
def get_rank():
    items = []
    r1 = get_html(netease_api + '/toplist')
    j1 = json.loads(r1)
    one63list = j1['list']
    for index in range(len(one63list)):
        gd = {}
        gd['name'] = u'网易云音乐 · '+ one63list[index]['name']
        gd['thumb'] = one63list[index]['coverImgUrl']
        gd['url'] = '163|' + str(one63list[index]['id'])
        gd['desc'] = one63list[index]['description']
        items.append(gd)

    r2 = get_html(qqmusic_api + '/top/category')
    j2 = json.loads(r2)
    qqlist = j2['data']
    for index in range(len(qqlist)):
        listlist = qqlist[index]['list']
        for i in range(len(listlist)):
            if listlist[i]['topId'] != 201:
                gd = {}
                gd['name'] = u'QQ音乐 · '+ listlist[i]['label']
                gd['thumb'] = listlist[i]['picUrl']
                gd['url'] = 'qq|' + str(listlist[i]['topId'])
                gd['desc'] = listlist[i]['updateTime'] + u'更新'
                items.append(gd)
    return items
########################################### 排行详细 ###########################################
def one63rank(value):
    gedans = []
    # r = get_html(netease_api + '/top/list?idx=' + value)
    r = get_html(netease_api + '/related/playlist?id=' + value)
    dialog = xbmcgui.Dialog()
    dialog.textviewer('错误提示', str(value))
    j = json.loads(r)
    glist = j['playlist']['tracks']
    # songs = ''
    # for index in range(len(glist)):
    #     if index == 0:
    #         songs += str(glist[index]['id'])
    #     else:
    #         songs += ',' + str(glist[index]['id'])
    # #mp3 url
    # r2 = get_html(netease_api + '/song/url?id=' + songs)
    # j2 = json.loads(r2)
    # mp3url = j2['data']
    for index in range(len(glist)):
        gd ={}
        gd['name'] = glist[index]['name']
        gd['label'] = glist[index]['name']
        if glist[index]['alia'] != []:
            gd['label'] +=  u'(' + glist[index]['alia'][0] + u')'
        gd['thumb'] = glist[index]['al']['picUrl']
        # gd['url'] = mp3url[index]['url']
        if xbmcplugin.getSetting(int(sys.argv[1]), 'httpswitch') == 'true':
            gd['url'] = 'http'
        else:
            gd['url'] = 'https'
        gd['url'] += '://music.163.com/song/media/outer/url?id=' + str(glist[index]['id']) + '.mp3'
        gedans.append(gd)
    return gedans

def qqrank(value):
    gedans = []
    # dialog = xbmcgui.Dialog()
    # dialog.textviewer('错误提示', str(value))
    r = get_html(qqmusic_api + '/top?id=' + str(value))
    j = json.loads(r)
    glist = j['data']['list']
    songs= ''
    for index in range(len(glist)):
        if index == 0:
            songs += glist[index]['mid']
        else:
            songs += ',' + glist[index]['mid']
    r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
    j1 = json.loads(r1)
    mp3urls = j1['data']
    
    for index in range(len(glist)):
        
        if glist[index]['mid'] in mp3urls:
            gd ={}
            gd['name'] = glist[index]['title']
            gd['label'] = ''
            if int(glist[index]['rankType']) == 1:
                gd['label'] += u'[COLOR red]↑ ' + glist[index]['rankValue'] + u' '*(3-len(str(glist[index]['rankValue']))) +  u'[/COLOR]'
            if int(glist[index]['rankType']) == 2:
                gd['label'] += u'[COLOR green]↓ ' + glist[index]['rankValue'] + u' '*(3-len(str(glist[index]['rankValue']))) + u'[/COLOR]'
            if int(glist[index]['rankType']) == 3:
                gd['label'] += u'= ' + glist[index]['rankValue'] + u' '*(3-len(str(glist[index]['rankValue'])))
            if int(glist[index]['rankType']) == 4:
                gd['label'] += u'[COLOR red]NEW[/COLOR]'
            if int(glist[index]['rankType']) == 6:
                gd['label'] += u'[COLOR red]↑ ' + glist[index]['rankValue'] + u'[/COLOR]' + u' '*(5-len(str(glist[index]['rankValue'])))
            gd['label'] += u' ' +  glist[index]['title']
            gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['albumMid'] + '.jpg'
            gd['url'] = mp3urls[glist[index]['mid']]
            gedans.append(gd)
    return gedans
########################################### mv ###########################################
def one63mvlist(page):
    items = []
    r = get_html(netease_api + '/mv/all?limit=50&offset=' + str( ( int(page)-1 ) *50 ) )
    j = json.loads(r)
    one63list = j['data']
    for index in range(len(one63list)):
        gd = {}
        gd['name'] = one63list[index]['name']
        gd['thumb'] = one63list[index]['cover']
        gd['url'] = 'https://music.163.com/#/mv?id=' +str(one63list[index]['id'])
        items.append(gd)
    return items

def qqmvlist(page):
    items = []
    r = get_html(qqmusic_api + '/mv/list?pageSize=50&pageNo=' + str(page))
    j = json.loads(r)
    listlist = j['data']['list']
    for i in range(len(listlist)):
        gd = {}
        gd['name'] = listlist[i]['title']
        gd['thumb'] = listlist[i]['picurl']
        gd['url'] = 'https://y.qq.com/n/yqq/mv/v/'+listlist[i]['vid']+'.html'
        items.append(gd)
    return items

def one63playmv(vid):
    r = get_html(netease_api + '/mv/url?id=' + str(vid))
    j = json.loads(r)
    mp4 = j['data']['url']
    return mp4

def qqplaymv(vid):
    r = get_html(qqmusic_api + '/mv/url?id=' + str(vid))
    j = json.loads(r)
    mp4 = j['data'][vid][len( j['data'][vid])-1]
    return mp4

def one63mvinfo(vid):
    vdict = {}
    r = get_html(netease_api + '/mv/detail?mvid=' + str(vid))
    j = json.loads(r)
    i = j['data']
    vdict['title'] = i['name']
    vdict['thumb'] = i['cover']
    vdict['duration'] = int(str(i['duration'])[:-3])
    vdict['plot'] = zh(i['playCount']) + '播放 · ' + zh(i['commentCount']) + '评论'
    if i['desc']:
        vdict['plot'] += '\n\n' + i['desc'].encode('utf-8')
    vdict['aired'] = i['publishTime']

    cast = []
    for index in range(len(i['artists'])):
        cast.append(i['artists'][index]['name'])
    vdict['cast'] = cast
    return vdict

def qqmvinfo(vid):
    vdict = {}
    r = get_html(qqmusic_api + '/mv?id=' + str(vid))
    j = json.loads(r)
    i = j['data']['info']
    vdict['title'] = i['name']
    vdict['thumb'] = i['cover_pic']
    vdict['duration'] = i['duration']
    vdict['plot'] = zh(i['playcnt']) + '播放'
    if i['desc']:
        vdict['plot'] = i['desc']
    vdict['aired'] = unix_to_data(i['pubdate'])

    cast = []
    for index in range(len(i['singers'])):
        cast.append(i['singers'][index]['name'])
    vdict['cast'] = cast
    return vdict
########################################### 搜索 ###########################################
def one63search(keyword,type,page):
    gedans = []
    r = get_html(netease_api + '/search?keywords=' + keyword + '&offset='+str((int(page)-1)*30)+'&type='+type)
    j = json.loads(r)
    glist = j['result']
    #单曲
    if type == '1':
        if 'songs' in glist:
            glist = glist['songs']
            songs= ''
            for index in range(len(glist)):
                if index == 0:
                    songs += str(glist[index]['id'])
                else:
                    songs += ',' + str(glist[index]['id'])
            #mp3详情
            r2 = get_html(netease_api + '/song/detail?ids=' + songs)
            j2 = json.loads(r2)
            mp3detail = j2['songs']
    
            for index in range(len(glist)):
                gd ={}
                gd['name'] = mp3detail[index]['name']
                gd['thumb'] = mp3detail[index]['al']['picUrl']
                #mp3url
                r1 = get_html(netease_api + '/song/url?id=' + str(mp3detail[index]['id']))
                j1 = json.loads(r1)
                gdurl = j1['data'][0]['url']
                gd['url'] = gdurl
                #gd['url'] = mp3urls[str(mp3detail[index]['id'])]
                gd['info'] = {'title':mp3detail[index]['name'],'album':mp3detail[index]['al']['name'],'artist':mp3detail[index]['ar'][0]['name']}
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    #歌单
    if type == '1000':
        if 'playlists' in glist:
            glist = glist['playlists']
            for index in range(len(glist)):
                gd ={}
                gd['name'] = glist[index]['name']
                gd['thumb'] = glist[index]['coverImgUrl']
                gd['url'] = 'https://music.163.com/#/playlist?id=' + str(glist[index]['id'])
                ginfo =  {'title':glist[index]['name'],'cast':[(glist[index]['creator']['nickname'],u'创建者')],'plot':zh(glist[index]['playCount']).decode('utf-8') + u'播放 · ' + zh(glist[index]['trackCount']).decode('utf-8') + u'首歌 \n\n'}
                if glist[index]['description']:
                    ginfo['plot'] += glist[index]['description']
                gd['info'] = ginfo
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    #专辑
    if type == '10':
        if 'albums' in glist:
            glist = glist['albums']
            for index in range(len(glist)):
                gd ={}
                gd['name'] = glist[index]['name']
                gd['thumb'] = glist[index]['blurPicUrl']
                gd['url'] = 'https://music.163.com/#/album?id=' + str(glist[index]['id'])
                gd['info'] = {'title':glist[index]['name'],'album':glist[index]['name'],'artist':glist[index]['artists'][0]['name']}
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    #歌手
    if type == '100':
        if 'artists' in glist:
            glist = glist['artists']
            for index in range(len(glist)):
                gd ={}
                gd['name'] = glist[index]['name']
                gd['thumb'] = glist[index]['picUrl']
                gd['url'] = 'https://music.163.com/#/artist?id=' + str(glist[index]['id'])
                gd['info'] = {'title':glist[index]['name'],'artist':glist[index]['name']}
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    #MV
    if type == '1004':
        if 'mvs' in glist:
            glist = glist['mvs']
            for index in range(len(glist)):
                gd ={}
                gd['name'] = glist[index]['name']
                gd['thumb'] = glist[index]['cover']
                gd['url'] = 'https://music.163.com/#/mv?id=' + str(glist[index]['id'])
                gd['info'] = {'title':glist[index]['name'],'duration':int(glist[index]['duration'])/1000,'cast':[glist[index]['artistName']]}
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    #视频
    if type == '1014':
        if 'videos' in glist:
            glist = glist['videos']
            for index in range(len(glist)):
                gd ={}
                gd['name'] = glist[index]['title']
                gd['thumb'] = glist[index]['coverUrl']
                gd['url'] = 'https://music.163.com/#/video?id=' + str(glist[index]['vid'])
                gd['info'] = {'title':glist[index]['title'],'duration':int(glist[index]['durationms'])/1000,'cast':[glist[index]['creator'][0]['userName']]}
                gedans.append(gd)
        else:
            dialog = xbmcgui.Dialog()
            dialog.notification('提示', '搜索结果为空', xbmcgui.NOTIFICATION_INFO, 5000)
    return gedans

def qqsearch(keyword,type,page):
    gedans = []
    r = get_html(qqmusic_api + '/search?key=' + keyword + '&pageSize=30&pageNo='+str(page)+'&t='+type)
    j = json.loads(r)
    glist = j['data']['list']
    #单曲
    if type == '0':
        songs= ''
        for index in range(len(glist)):
            if index == 0:
                songs += glist[index]['songmid']
            else:
                songs += ',' + glist[index]['songmid']
        r1 = get_html(qqmusic_api + '/song/urls?id=' + songs)
        j1 = json.loads(r1)
        mp3urls = j1['data']
    
        for index in range(len(glist)):
        
            if glist[index]['songmid'] in mp3urls:
                gd ={}
                gd['name'] = glist[index]['songname']
                gd['thumb'] = 'http://y.gtimg.cn/music/photo_new/T002R300x300M000' + glist[index]['albummid'] + '.jpg'
                gd['url'] = mp3urls[glist[index]['songmid']]
                gd['info'] = {'title':glist[index]['songname'],'album':glist[index]['albumname'],'artist':glist[index]['singer'][0]['name']}
                gedans.append(gd)
    #歌单
    if type == '2':
        for index in range(len(glist)):
            gd ={}
            gd['name'] = unescape(glist[index]['dissname'].encode('utf-8')).decode('utf-8')
            gd['thumb'] = glist[index]['imgurl']
            gd['url'] = 'https://y.qq.com/n/yqq/playlist/' + str(glist[index]['dissid']) + '.html'
            gd['info'] = {'title':unescape(glist[index]['dissname'].encode('utf-8')).decode('utf-8'),'cast':[glist[index]['creator']['name'],u'创建者'],'plot':zh(glist[index]['listennum']).decode('utf-8') + u' 播放 \n\n' + unescape(glist[index]['introduction'].encode('utf-8')).decode('utf-8')}
            gedans.append(gd)
    #专辑
    if type == '8':
        for index in range(len(glist)):
            gd ={}
            gd['name'] = glist[index]['albumName']
            gd['thumb'] = glist[index]['albumPic']
            gd['url'] = 'https://y.qq.com/n/yqq/album/' + str(glist[index]['albumMID']) + '.html'
            gd['info'] = {'title':glist[index]['albumName'],'album':glist[index]['albumName'],'artist':glist[index]['singerName']}
            gedans.append(gd)
    #歌手
    if type == '9':
        for index in range(len(glist)):
            gd ={}
            gd['name'] = glist[index]['singerName']
            gd['thumb'] = glist[index]['singerPic']
            gd['url'] = 'https://y.qq.com/n/yqq/singer/' + str(glist[index]['singerMID']) + '.html'
            gd['info'] = {'title':glist[index]['singerName'],'artist':glist[index]['singerName']}
            gedans.append(gd)
    #MV
    if type == '12':
        for index in range(len(glist)):
            gd ={}
            gd['name'] = glist[index]['mv_name']
            gd['thumb'] = glist[index]['mv_pic_url']
            gd['url'] = 'https://y.qq.com/n/yqq/mv/v/' + str(glist[index]['v_id']) + '.html'
            gd['info'] = {'title':glist[index]['mv_name'],'duration':glist[index]['duration']}
            gedans.append(gd)
    return gedans
########################################### 网易云视频 ###########################################
def one63playvideo(vid):
    r = get_html(netease_api + '/video/url?id=' + str(vid))
    j = json.loads(r)
    mp4 = j['urls'][0]['url']
    return mp4

def one63videoinfo(vid):
    vdict = {}
    r = get_html(netease_api + '/video/detail?id=' + str(vid))
    j = json.loads(r)
    i = j['data']
    vdict['title'] = i['title']
    vdict['thumb'] = i['coverUrl']
    vdict['duration'] = int(i['durationms']/1000)
    vdict['plot'] = zh(i['playTime']) + '播放 · ' + zh(i['praisedCount']) + '赞 · ' + zh(i['commentCount']) + '评论'
    if i['description']:
        vdict['plot'] += '\n\n' + i['description'].encode('utf-8')
    vdict['aired'] = unix_to_data(i['publishTime'])
    genre = []
    for index in range(len(i['videoGroup'])):
        genre.append(i['videoGroup'][index]['name'])

    vdict['cast'] = [(i['creator']['nickname'],'视频作者')]
    vdict['genre'] = genre
    vdict['tag'] = genre
    return vdict


@plugin.route('/')
def index():
    items = []
    items.append({
        'label': '推荐',
        'path': plugin.url_for('tuijian'),
    })
    items.append({
        'label': '排行',
        'path': plugin.url_for('rank'),
    })
    items.append({
        'label': 'MV',
        'path': plugin.url_for('mv'),
    })
    items.append({
        'label': '搜索',
        'path': plugin.url_for('so'),
    })
    items.append({
        'label': '歌单',
        'path': plugin.url_for('gedang'),
    })
    items.append({
        'label': '日推',
        'path': plugin.url_for('ritui'),
    })
    # items.append({
    #     'label': '设置',
    #     'path': plugin.url_for('setting'),
    # })
    return items

@plugin.route('/tuijian/')
def tuijian():
    items = []
    items.append({
        'label': '网易云 · 热门推荐歌单',
        'path': plugin.url_for('get_tuijian',mode='163'),
    })
    items.append({
        'label': 'QQ音乐 · 热门推荐歌单',
        'path': plugin.url_for('get_tuijian',mode='qq'),
    })
    return items

@plugin.route('/ritui/')
def ritui():
    if xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusiccookieswitch') == 'true' or xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookieswitch') == 'true':
        items = []
        if xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicu') != '' and xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusiccookieswitch') == 'true':
            items.append({
                'label': '网易云 · 私人推荐',
                'path': plugin.url_for('get_ritui',mode='163'),
            })
        if xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookie') != '' and xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookieswitch') == 'true':
            items.append({
                'label': 'QQ音乐 · 私人推荐',
                'path': plugin.url_for('get_ritui',mode='qq'),
            })
        
        return items
    else:
        dialog = xbmcgui.Dialog()
        dialog.notification('该功能未解锁','请先启用QQ音乐或者网易云的cookie功能', xbmcgui.NOTIFICATION_INFO, 5000)

@plugin.route('/mv/')
def mv():
    items = []
    items.append({
        'label': '网易云 · MV',
        'path': plugin.url_for('get_mv',mode='163',page=1),
    })
    items.append({
        'label': 'QQ音乐 · MV',
        'path': plugin.url_for('get_mv',mode='qq',page=1),
    })
    return items

@plugin.route('/so/')
def so():
    items = []
    items.append({
        'label': '网易云 · 单曲搜索',
        'path': plugin.url_for('history',name='搜索 网易云 · 单曲',url='search',mode='163',type='1')
    })
    items.append({
        'label': 'QQ音乐 · 单曲搜索',
        'path': plugin.url_for('history',name='搜索 QQ音乐 · 单曲',url='search',mode='qq',type='0')
    })
    items.append({
        'label': '网易云 · 专辑搜索',
        'path': plugin.url_for('history',name='搜索 网易云 · 专辑',url='search',mode='163',type='10')
    })
    items.append({
        'label': 'QQ音乐 · 专辑搜索',
        'path': plugin.url_for('history',name='搜索 QQ音乐 · 专辑',url='search',mode='qq',type='8')
    })
    items.append({
        'label': '网易云 · 歌手搜索',
        'path': plugin.url_for('history',name='搜索 网易云 · 歌手',url='search',mode='163',type='100')
    })
    items.append({
        'label': 'QQ音乐 · 歌手搜索',
        'path': plugin.url_for('history',name='搜索 QQ音乐 · 歌手',url='search',mode='qq',type='9')
    })
    items.append({
        'label': '网易云 · 歌单搜索',
        'path': plugin.url_for('history',name='搜索 网易云 · 歌单',url='search',mode='163',type='1000')
    })
    items.append({
        'label': 'QQ音乐 · 歌单搜索',
        'path': plugin.url_for('history',name='搜索 QQ音乐 · 歌单',url='search',mode='qq',type='2')
    })
    items.append({
        'label': '网易云 · MV搜索',
        'path': plugin.url_for('history',name='搜索 网易云 · MV',url='search',mode='163',type='1004')
    })
    items.append({
        'label': 'QQ音乐 · MV搜索',
        'path': plugin.url_for('history',name='搜索 QQ音乐 · MV',url='search',mode='qq',type='12')
    })
    # items.append({
    #     'label': '网易云 · 电台搜索',
    #     'path':  plugin.url_for('history',name='搜索 网易云 · 电台',url='search',mode='163',type='1009')
    # })
    items.append({
        'label': '网易云 · 视频搜索',
        'path':  plugin.url_for('history',name='搜索 网易云 · 视频',url='search',mode='163',type='1014')
    })
    # items.append({
    #     'label': '复制粘贴歌单url解析歌单(支持网易云和QQ音乐)',
    #     'path': plugin.url_for('get_mv',mode='163',page=1),
    # })
    # items.append({
    #     'label': '复制粘贴MV url解析mv(支持网易云和QQ音乐)',
    #     'path': plugin.url_for('get_mv',mode='163',page=1),
    # })
    return items

@plugin.route('/gedang/')
def gedang():
    if xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusiccookieswitch') == 'true' or xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookieswitch') == 'true':
        items = []
        if xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusicuid') != '' and xbmcplugin.getSetting(int(sys.argv[1]), 'neteasemusiccookieswitch') == 'true':
            items.append({
                'label': '网易云 · 我的歌单',
                'path': plugin.url_for('get_gedang',mode='163'),
            })
        if xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusicid') != '' and xbmcplugin.getSetting(int(sys.argv[1]), 'qqmusiccookieswitch') == 'true':
            items.append({
                'label': 'QQ音乐 · 我的歌单',
                'path': plugin.url_for('get_gedang',mode='qq'),
            })
        return items
    else:
        dialog = xbmcgui.Dialog()
        dialog.notification('该功能未解锁','请先启用QQ音乐或者网易云的cookie功能', xbmcgui.NOTIFICATION_INFO, 5000)

@plugin.route('/rank/')
def rank():
    gdlist = get_rank()
    items = [{
        'label': video['name'],
        'path': plugin.url_for('ranklist',value=video['url'].encode('utf-8')),
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'info':{'plot':video['desc'],'mediatype':'video'},
        'info_type':'video',
    } for video in gdlist]
    return items

@plugin.route('/ranklist/<value>/')
def ranklist(value):
    # 通过传递 qq|排行榜id 或 163|排行榜id 的value值 来区分不同的排行榜
    value = value.split("|")
    if value[0] == '163':
        gdlist = one63playlist(value[1])
    if value[0] == 'qq':
        gdlist = qqrank(value[1])
    
    items = []
    for video in gdlist:
        try:
            label = video['label']
        except:
            label = video['name']
        items.append({
        'label': label,
        'path': video['url'],
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'is_playable': True,
        'info':{'title':video['name'],'mediatype':'music'},
        'info_type':'music',
    } )
    return items

@plugin.route('/get_mv/<mode>/<page>/')
def get_mv(mode,page):
    if mode == '163':
        gdlist = one63mvlist(int(page))
    else:
        gdlist = qqmvlist(int(page))
        
    items = [{
        'label': video['name'],
        'path': plugin.url_for('playmv',url=video['url']),
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
    } for video in gdlist]
    if len(gdlist) == 50:
        items.append({
            'label': '下一页',
            'path': plugin.url_for('get_mv',mode=mode,page=(int(page)+1)),
        })
    return items

@plugin.route('/get_tuijian/<mode>/')
def get_tuijian(mode):
    items = []
    if mode == '163':
        gdlist = one63tuijiangedan()
    else:
        gdlist = qqtuijiangedan()
    for video in gdlist:
        info = video['info']
        info['mediatype'] = 'video'
        items.append({
            'label': video['name'],
            'path': plugin.url_for('playlist',url=video['url']),
	    'thumbnail': video['thumb'],
            'icon': video['thumb'],
            'info':info,
            'info_type':'video',
        })
    return items

@plugin.route('/get_ritui/<mode>/')
def get_ritui(mode):
    items = []
    if mode == '163':
        items.append({
            'label':'每日推荐',
            'thumbnail':'https://iph.href.lu/200x200?text='+time.strftime("%d", time.localtime()) +'&fg=FFFFFF&bg=FF0000',
            'icon':'https://iph.href.lu/200x200?text='+time.strftime("%d", time.localtime()) +'&fg=FFFFFF&bg=FF0000',
            'path': plugin.url_for('rituilist',mode='163'),
        })
        gdlist = one63weinituijian()
    else:
        items.append({
            'label':'今日私享',
            'thumbnail':'http://y.qq.com/m/resource/calendar/'+time.strftime("%m%d", time.localtime()) +'_300.jpg',
            'icon':'http://y.qq.com/m/resource/calendar/'+time.strftime("%m%d", time.localtime()) +'_300.jpg',
            'path': plugin.url_for('rituilist',mode='qq'),
        })
        gdlist = qqweinituijian()
    for video in gdlist:
        info = video['info']
        info['mediatype'] = 'video'
        items.append({
            'label': video['name'],
            'path': plugin.url_for('playlist',url=video['url']),
	    'thumbnail': video['thumb'],
            'icon': video['thumb'],
            'info':info,
            'info_type':'video',
            'context_menu':[('Theater Showtimes', 'RunScript(special://home/scripts/showtimes/default.py,Iron Man)')]
        })
    return items

@plugin.route('/rituilist/<mode>/')
def rituilist(mode):
    
    items = []
    if mode == '163':
        gdlist = one63ritui()
    else:
        gdlist = qqritui()
    items = [{
        'label': video['name'],
        'path': video['url'],
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'is_playable': True,
        'info':video['info'],
        'info_type':'music',
    } for video in gdlist]
    return items

@plugin.route('/get_gedang/<mode>/')
def get_gedang(mode):
    items = []
    if mode == '163':
        gdlist = one63gedan()
    else:
        gdlist = qqgedan()
        
    for video in gdlist:
        info = video['info']
        info['mediatype'] = 'video'
        items.append({
            'label': video['name'],
            'path': plugin.url_for('playlist',url=video['url']),
	    'thumbnail': video['thumb'],
            'icon': video['thumb'],
            'info':info,
            'info_type':'video',
        })
    return items

@plugin.route('/playlist/<url>/')
def playlist(url):
    items = []
    if 'playlist' in url:
        dialog = xbmcgui.Dialog()
        if '163.com' in url:
            #网易云
            if re.search('(?<=playlist\?id=)\d+',url):
                pid = re.search('(?<=playlist\?id=)\d+',url).group()
                gdlist = one63playlist(pid)
                dialog.notification('提取网易云音乐歌单成功','歌单号:'+str(pid), xbmcgui.NOTIFICATION_INFO, 5000)
        else:
            if 'qq.com' in url:
                #qq音乐
                if re.search('(?<=playlist/)\d+',url):
                    pid = re.search('(?<=playlist/)\d+',url).group()
                    gdlist = qqplaylist(pid)
                    dialog.notification('提取QQ音乐歌单成功','歌单号:'+str(pid), xbmcgui.NOTIFICATION_INFO, 5000)
    else:
        #非法url
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '无法识别的歌单url')
    items = [{
        'label': video['name'],
        'path': video['url'],
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'is_playable': True,
        'info':video['info'],
        'info_type':'music',
    } for video in gdlist]
    return items

@plugin.route('/playmv/<url>/')
def playmv(url):
    items = []
    # dialog = xbmcgui.Dialog()
    # ok = dialog.ok('错误提示', str(url))
    if 'mv' in url:
        if '163.com' in url:
            #网易云
            if re.search('(?<=mv\?id=)\d+',url):
                vid = re.search('(?<=mv\?id=)\d+',url).group()
                mp4url = one63playmv(vid)
                mp4info = one63mvinfo(vid)
        else:
            if 'qq.com' in url:
                #qq音乐
                if re.search('(?<=mv/v/)[a-zA-Z0-9]+',url):
                    vid = re.search('(?<=mv/v/)[a-zA-Z0-9]+',url).group()
                    mp4url = qqplaymv(vid)
                    mp4info = qqmvinfo(vid)
        #dialog = xbmcgui.Dialog()
        #ok = dialog.ok('错误提示', vid)
        mp4info['mediatype'] = 'video'
        items.append({
            'label': mp4info['title'],
            'path': mp4url,
	    'thumbnail': mp4info['thumb'],
            'icon': mp4info['thumb'],
            'is_playable': True,
            'info':mp4info,
            'info_type':'video',
        })
    else:
        #非法url
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '无法识别的MVurl')
    return items

@plugin.route('/playvideo/<url>/')
def playvideo(url):
    items = []
    # dialog = xbmcgui.Dialog()
    # ok = dialog.ok('错误提示', str(url))
    if 'video' in url and '163.com' in url:
        #网易云
        if re.search('(?<=video\?id=)[a-zA-Z0-9]+',url):
            vid = re.search('(?<=video\?id=)[a-zA-Z0-9]+',url).group()
            mp4url = one63playvideo(vid)
            mp4info = one63videoinfo(vid)
        
        #dialog = xbmcgui.Dialog()
        #ok = dialog.ok('错误提示', vid)
        mp4info['mediatype'] = 'video'
        items.append({
            'label': mp4info['title'],
            'path': mp4url,
	    'thumbnail': mp4info['thumb'],
            'icon': mp4info['thumb'],
            'is_playable': True,
            'info':mp4info,
            'info_type':'video',
        })
    else:
        #非法url
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '无法识别的视频url')
    return items

@plugin.route('/playalbum/<url>/')
def playalbum(url):
    items = []
    if 'album' in url:
        if '163.com' in url:
            #网易云
            if re.search('(?<=album\?id=)\d+',url):
                pid = re.search('(?<=album\?id=)\d+',url).group()
                gdlist = one63album(pid)
        else:
            if 'qq.com' in url:
                #qq音乐
                if re.search('(?<=album/)[a-zA-Z0-9]+',url):
                    pid = re.search('(?<=album/)[a-zA-Z0-9]+',url).group()
                    gdlist = qqalbum(pid)
        # dialog = xbmcgui.Dialog()
        # ok = dialog.ok('错误提示', pid)
    else:
        #非法url
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '无法识别的专辑url')
    items = [{
        'label': video['name'],
        'path': video['url'],
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'is_playable': True,
        'info':{'title':video['name'],'mediatype':'album'},
        'info_type':'music',
    } for video in gdlist]
    return items

@plugin.route('/playsinger/<url>/')
def playsinger(url):
    items = []
    if 'artist' in url or 'singer' in url:
        if '163.com' in url:
            #网易云
            if re.search('(?<=artist\?id=)\d+',url):
                pid = re.search('(?<=artist\?id=)\d+',url).group()
                gdlist = one63singer(pid)
        else:
            if 'qq.com' in url:
                #qq音乐
                if re.search('(?<=singer/)[a-zA-Z0-9]+',url):
                    pid = re.search('(?<=singer/)[a-zA-Z0-9]+',url).group()
                    gdlist = qqsinger(pid)
        # dialog = xbmcgui.Dialog()
        # ok = dialog.ok('错误提示', pid)
    else:
        #非法url
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '无法识别的歌手url')
    items = [{
        'label': video['name'],
        'path': video['url'],
	'thumbnail': video['thumb'],
        'icon': video['thumb'],
        'is_playable': True,
        'info':{'title':video['name'],'mediatype':'album'},
        'info_type':'music',
    } for video in gdlist]
    return items

@plugin.route('/labels/<label>/')
def show_label(label):
    # 写抓取视频类表的方法
    #
    items = [
        {'label': label},
    ]
    return items

# @plugin.route('/setting')
# def setting():
#     items = []
#     items.append({
#         'label': u'设置网易云音乐API (API:'+netease_api +')',
#         'path': plugin.url_for('input',key='one63api',value='请输入网易云音乐API地址:'),
#     })
#     items.append({
#         'label': u'设置QQ音乐API (API:'+qqmusic_api +')',
#         'path': plugin.url_for('input',key='qqapi',value='请输入QQ音乐API地址:'),
#     })
#     # items.append({
#     #     'label': u'设置咪咕音乐API (API:'+cache['miguapi'] +')',
#     #     'path': plugin.url_for('input',key='miguapi',value='请输入咪咕音乐API地址:'),
#     # })
#     if cache['my163num'] == '':
#         items.append({
#             'label': u'设置网易云uid - 解锁基础功能(获取公开歌单,喜欢的歌等)',
#             'path': plugin.url_for('input',key='my163num',value='请输入网易云uid的值:'),
#         })
#     else:
#         items.append({
#             'label': u'设置网易云uid (uid:'+cache['my163num'] +')',
#             'path': plugin.url_for('input',key='my163num',value='请输入网易云uid的值:'),
#         })
#     if cache['myqqnum'] == '':
#         items.append({
#             'label': u'设置QQ号 - 解锁基础功能(获取公开歌单,喜欢的歌等)',
#             'path': plugin.url_for('input',key='myqqnum',value='请输入QQ号:'),
#         })
#     else:
#         items.append({
#             'label': u'设置QQ号 (QQ号:'+ cache['myqqnum'] +')',
#             'path': plugin.url_for('input',key='myqqnum',value='请输入QQ号:'),
#         })
#     if cache['my163'] == '':
#         items.append({
#             'label': u'设置网易云MUSIC_U - 解锁高级功能(专属日推)',
#             'path': plugin.url_for('input',key='my163',value='请输入网易云MUSIC_U的值:'),
#         })
#     else:
#         items.append({
#             'label': u'设置网易云MUSIC_U (MUSIC_U:'+cache['my163'] +')',
#             'path': plugin.url_for('input',key='my163',value='请输入网易云MUSIC_U的值:'),
#         })
#     if cache['myqq'] == '':
#         items.append({
#             'label': u'设置QQ cookie - 解锁高级功能(专属日推)',
#             'path': plugin.url_for('input',key='myqq',value='请输入QQ cookie:'),
#         })
#     else:
#         items.append({
#             'label': u'设置QQ cookie (QQ cookies:'+ cache['myqq'] +')',
#             'path': plugin.url_for('input',key='myqq',value='请输入QQ cookie:'),
#         })
#     return items

@plugin.route('/input/<key>/<value>/')
def input(key,value):
    keyboard = xbmc.Keyboard('', value)
    xbmc.sleep(1500)
    keyboard.doModal()
    if (keyboard.isConfirmed()):
        dialog = xbmcgui.Dialog()
        ret = dialog.yesno('确认该值正确吗?', keyboard.getText())
        if ret:
            cache[key] = keyboard.getText()
            dialog = xbmcgui.Dialog()
            dialog.notification('提示','保存成功', xbmcgui.NOTIFICATION_INFO, 5000,False)


@plugin.route('/search/<value>/<page>/<type>/<mode>/')
def search(value,page,type,mode):
    if value == 'null':
        keyboard = xbmc.Keyboard('', '请输入搜索内容')
        xbmc.sleep(1500)
        keyboard.doModal()
        hi = his['search']
        if (keyboard.isConfirmed()):
            keyword = keyboard.getText()
            if keyword != '':
                hi[keyword] = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    else:
        keyword = value
    if 'keyword' in dir():
        if mode == '163':
            videos = one63search(keyword,type,page)
        else:
            videos = qqsearch(keyword,type,page)
        items = []
    
        for video in videos:
            info = video['info']
            #mv
            if type == '1004' or type == '12':
                info['mediatype'] = 'video'
                info_type = 'video'
                items.append({'label': video['name'],
                'path': plugin.url_for('playmv', url=video['url']),
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                })
            #歌单
            if type == '2' or type == '1000':
                info['mediatype'] = 'video'
                info_type = 'video'
                items.append({'label': video['name'],
                'path': plugin.url_for('playlist', url=video['url']),
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                })
            #单曲
            if type == '0' or type == '1':
                info['mediatype'] = 'song'
                info_type = 'music'
                items.append({'label': video['name'],
                'path': video['url'],
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                'is_playable': True,
                })
            #专辑
            if type == '8' or type == '10':
                info['mediatype'] = 'album'
                info_type = 'music'
                items.append({'label': video['name'],
                'path': plugin.url_for('playalbum', url=video['url']),
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                })
            #歌手
            if type == '9' or type == '100':
                info['mediatype'] = 'artist'
                info_type = 'music'
                items.append({'label': video['name'],
                'path': plugin.url_for('playsinger', url=video['url']),
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                })
            #视频
            if type == '1014':
                info['mediatype'] = 'video'
                info_type = 'video'
                items.append({'label': video['name'],
                'path': plugin.url_for('playvideo', url=video['url']),
            'thumbnail': video['thumb'],
                'icon': video['thumb'],
                'info': info,
                'info_type':info_type,
                })
        if len(videos) == 30:
            items.append({
                'label': '下一页',
                'path': plugin.url_for('search',value=value,page=(int(page)+1),mode=mode,type=type),
            })
        
    
        return items

def get_key (dict, value):
  return [k for k, v in dict.items() if v == value]

@plugin.route('/history/<name>/<url>/<type>/<mode>/')
def history(name,url,type,mode):
    items = []
    items.append({
        'label': '[COLOR yellow]'+ name +'[/COLOR]',
        'path': plugin.url_for(url,value='null',page=1,mode=mode,type=type),
    })
    #his[url] ={'aaa':'2019-01-23 10:00:00','bbb':'2019-01-23 09:01:00','ccc':'2019-01-23 09:00:59'}
    if url in his:
        hi = his[url]
        
    else:
        his[url] = {}
        hi = his[url]
        
    #hi = []
    if hi:
        val = list(hi.values())
        val = sorted(val,reverse=True)
        for index in range(len(val)):
            items.append({
                'label': name+ ':' +get_key(hi,val[index])[0] + ' - [查询时间:' + val[index] +']',
                'path': plugin.url_for(url,value=get_key(hi,val[index])[0],page=1,mode=mode,type=type),
            })
        items.append({
            'label': '[COLOR yellow]清除历史记录[/COLOR]',
            'path': plugin.url_for('cleanhis',url=url),
        })
    else:
        items.append({
            'label': '[COLOR yellow]历史记录为空[/COLOR]',
            'path': plugin.url_for(ok,value='历史记录为空'),
        })

    return items

@plugin.route('/ok/<value>/')
def ok(value):
    dialog = xbmcgui.Dialog()
    ok = dialog.ok('提示', value)

@plugin.route('/cleanhis/<url>/')
def cleanhis(url):
    his[url] = {}
    dialog = xbmcgui.Dialog()
    ok = dialog.ok('提示', '清理历史记录成功')

if __name__ == '__main__':
    plugin.run()


================================================
FILE: plugin.audio.jsososo/addon.xml
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.audio.jsososo" name="Jsososo" version="0.1.1" provider-name="zhengfan">
  <requires>
    <import addon="xbmc.python" version="2.1.0"/>
    <import addon="script.module.xbmcswift2" version="2.4.0"/>
  <import addon="script.module.beautifulsoup4" version="4.5.3"/>
  <import addon="script.module.requests" version="2.19.1"/>
  <import addon="script.module.html5lib" version="0.999.0"/>
  </requires>
  <extension point="xbmc.python.pluginsource" library="addon.py">
    <provides>audio</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language></language>
    <description>网易云音乐,QQ音乐,咪咕音乐聚合插件,API 1000%使用music.jsososo.com的服务</description>
    <assets>
      <icon>icon.png</icon>
      <fanart>fanart.png</fanart> 
    </assets>
    <news>首个版本</news>
  </extension>
</addon>


================================================
FILE: plugin.audio.jsososo/resources/__init__.py
================================================


================================================
FILE: plugin.audio.jsososo/resources/language/Chinese (Simple)/strings.po
================================================
msgid ""
msgstr ""

#Chinese Simplified

msgctxt "#32001"
msgid "api Setting"
msgstr "Api设置"

msgctxt "#32002"
msgid "api"
msgstr "Api 接口相关"

msgctxt "#32003"
msgid "neteasemusicapiurl"
msgstr "网易云音乐Api接口Url"

msgctxt "#32004"
msgid "qqmusicapiurl"
msgstr "QQ音乐Api接口Url"

msgctxt "#32005"
msgid "miguapiurl"
msgstr "咪咕音乐Api接口Url"

msgctxt "#32006"
msgid "mixapiswitch"
msgstr "启用Mix统一Api接口(启用后以上设置失效)"

msgctxt "#32007"
msgid "mixapiurl"
msgstr "Mix统一Api接口Url"

msgctxt "#32101"
msgid "163 Setting"
msgstr "网易云设置"

msgctxt "#32102"
msgid "cookie Setting"
msgstr "cookie相关"

msgctxt "#32103"
msgid "neteasemusicuid"
msgstr "Uid"

msgctxt "#32104"
msgid "neteasemusicu"
msgstr "MUSIC_U"

msgctxt "#32105"
msgid "neteasemusiccookieswitch"
msgstr "启用cookie(会将您的cookie发送到您设置的api服务器)"

msgctxt "#32106"
msgid "setting"
msgstr "功能设置"

msgctxt "#32107"
msgid "httpswitch"
msgstr "如果使用解锁网易云灰色后无法播放音乐请打开"

msgctxt "#32201"
msgid "qq Setting"
msgstr "QQ音乐设置"

msgctxt "#32203"
msgid "qqmusicid"
msgstr "QQ号"

msgctxt "#32204"
msgid "qqmusiccookie"
msgstr "QQ音乐cookie"

msgctxt "#32205"
msgid "qqmusiccookieswitch"
msgstr "启用cookie(会将您的cookie发送到您设置的api服务器)"

================================================
FILE: plugin.audio.jsososo/resources/language/English/strings.xml
================================================
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
  <!-- Plugin name -->
  <string id="30000">bilibili</string>
</strings>


================================================
FILE: plugin.audio.jsososo/resources/lib/__init__.py
================================================


================================================
FILE: plugin.audio.jsososo/resources/settings.xml
================================================
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
    <category label="32001">
      <setting label="32002" type="lsep"/>

      <setting id="neteasemusicapiurl" type="text" label="32003" default="http://music.jsososo.com/api"/>
      <setting id="qqmusicapiurl" type="text" label="32004" default="http://music.jsososo.com/apiQ"/>
      <setting id="miguapiurl" type="text" label="32005" default="http://api.migu.jsososo.com"/>


    </category>   
    <category label="32101">
      <setting label="32102" type="lsep"/>
      <setting label="32105" type="bool" id="neteasemusiccookieswitch" default="false"/>
      <setting id="neteasemusicuid" type="text" label="32103" default=""/>
      <setting id="neteasemusicu" type="text" label="32104" default=""/>
      <setting label="32106" type="lsep"/>
      <setting label="32107" type="bool" id="httpswitch" default="false"/>

    </category> 
    <category label="32201">
      <setting label="32102" type="lsep"/>
      <setting label="32205" type="bool" id="qqmusiccookieswitch" default="false"/>
      <setting id="qqmusicid" type="text" label="32203" default=""/>
      <setting id="qqmusiccookie" type="text" label="32204" default=""/>
    </category> 
</settings>


================================================
FILE: plugin.video.acfun/addon.py
================================================
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from xbmcswift2 import Plugin
import requests
from bs4 import BeautifulSoup
import xbmcgui
import base64
import json
import urllib2
import sys
import HTMLParser
import re
import time



def unescape(string):
    string = urllib2.unquote(string).decode('utf8')
    quoted = HTMLParser.HTMLParser().unescape(string).encode('utf-8')
    #转成中文
    return re.sub(r'%u([a-fA-F0-9]{4}|[a-fA-F0-9]{2})', lambda m: unichr(int(m.group(1), 16)), quoted)


plugin = Plugin()

reqid = 0
uid = '_26187_'
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'}
his = plugin.get_storage('his')
cache = plugin.get_storage('cache')

def del_kr(txt):
    while True:
        if re.search('\[(.*?)\]/(http|https):\/\/([\w.]+\/?)\S*/',txt):
            txt = txt.replace(re.search('\[(.*?)\]/(http|https):\/\/([\w.]+\/?)\S*/',txt).group(),'(图片)')
        else:
            if re.search('\[(.*?)\]',txt):
                txt = txt.replace(re.search('\[(.*?)\]',txt).group(),'(表情)')
            else:
                break
    return txt

def get_categories():
    return [{'name':'综合','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'番剧','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=155&subChannelId=&rankLimit=30&rankPeriod=WEEK'},
            {'name':'动画','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=1&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'娱乐','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=60&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'生活','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=201&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'音乐','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=58&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'舞蹈·偶像','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=123&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'游戏','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=59&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'科技','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=70&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'影视','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=68&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'体育','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=69&subChannelId=&rankLimit=100&rankPeriod=WEEK'},
            {'name':'鱼塘','link':'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=125&subChannelId=&rankLimit=100&rankPeriod=WEEK'}]

@plugin.cached(TTL=2)
def get_search(keyword, page):
    serachUrl = 'https://www.acfun.cn/rest/pc-direct/search/video?keyword=' + keyword + '&pCursor=' + str(page)

    r = requests.get(serachUrl, headers=headers)
    r.encoding = 'UTF-8'
    rtext = r.text
    j = json.loads(rtext)
    #dialog = xbmcgui.Dialog()
    #ok = dialog.ok('错误提示', str(j['videoList'][0]['id']))
    videos = []
    if 'videoList' in j:
        for index in range(len(j['videoList'])):
            videoitem = {}
            videoitem['name'] = j['videoList'][index]['title']
            videoitem['href'] = 'https://www.acfun.cn/v/ac'+ str(j['videoList'][index]['id'])
            videoitem['thumb'] = j['videoList'][index]['coverUrl']
            videos.append(videoitem)
        dialog = xbmcgui.Dialog()
        dialog.notification('当前'+ str(page) + '/' + str(j['pageNum']) + '页', '总共'+ str(j['totalNum']) + '个视频', xbmcgui.NOTIFICATION_INFO, 5000,False)
    else:
        dialog = xbmcgui.Dialog()
        ok = dialog.ok('错误提示', '搜索结果为空')
    return videos

@plugin.cached(TTL=2)
def get_bgm_search(keyword,page):
    serachUrl = 'https://www.acfun.cn/search?type=bgm&keyword=' + keyword + '&pCursor=' +str(page)
    videos = []
    r = requests.get(serachUrl, headers=headers)
    r.encoding = 'UTF-8'
    rtext = r.text
    rtext = rtext.encode('utf-8')
    soup = BeautifulSoup(rtext,'html.parser')
    bgmlist = soup.find('div',class_='bangumi-list')
    vlist = bgmlist.find_all('div',class_='search-bangumi')
    for index in range(len(vlist)):
        ahref = vlist[index].a['href']
        img = vlist[index].find('div',class_='bangumi__cover')
        title = img.img['alt']
        img = img.img['src']
        img = img.split('?')
        videoitem = {}
        videoitem['name'] = title
        videoitem['href'] = 'https://www.acfun.cn'+ ahref
        videoitem['thumb'] = img[0]
        videos.append(videoitem)
    return videos

@plugin.cached(TTL=2)
def get_up(uid,page):
    videos = []
    apiurl = 'https://www.acfun.cn/space/next?uid='+str(uid)+'&type=video&orderBy=2&pageNo=' +str(page)
    rec = requests.get(apiurl,headers=headers)
    #print(rec.text)
    j = json.loads(rec.text)
    dialog = xbmcgui.Dialog()
    dialog.notification('当前'+ str(j['data']['page']['pageNo']) + '/' + str(j['data']['page']['totalPage']) + '页', '总共'+ str(j['data']['page']['totalCount']) + '个视频', xbmcgui.NOTIFICATION_INFO, 5000,False)
    html = j['data']['html']
    soup = BeautifulSoup(html,'html.parser')
    #print(html)
    fig = soup.find_all('figure')
    #print(len(fig))
    for index in range(len(fig)):
        videoitem = {}
        videoitem['name'] = fig[index]['data-title']
        videoitem['href'] = 'https://www.acfun.cn'+fig[index]['data-url']
        videoitem['thumb'] = fig[index].img['src']
        videos.append(videoitem)
    return videos

@plugin.cached(TTL=2)
def get_comm(val,st):
    url = 'https://www.acfun.cn/rest/pc-direct/comment/list?sourceId=' + val + '&sourceType=' + st + '&page=1&pivotCommentId=&newPivotCommentId=&t=' +str(time.time())
    rec = requests.get(url,headers=headers)
    rec.encoding ='utf-8'
    #print(rec.text)

    j = json.loads(rec.text)
    n = '\n'
    text = ('*-'*20)+'热门评论'+('*-'*20) + '\n' +n
    hc = j['hotComments']
    scm = j['subCommentsMap']
    for index in range(len(hc)):
        text +='-----'*30 +n
        text +=hc[index]['userName'].encode('utf-8') + '      - 发表于'+ hc[index]['postDate'].encode('utf-8') +'\n' +n
        text +=del_kr(hc[index]['content'].encode('utf-8'))+'\n' +n
        text +='赞 '+hc[index]['likeCountFormat'].encode('utf-8')+ '      - 来自'+ hc[index]['deviceModel'].encode('utf-8') +n
        text +='-----'*30 +n
        if str(hc[index]['commentId']) in scm.keys():
            sc = scm[str(hc[index]['commentId'])]['subComments']
            for index in range(len(sc)):
                text +='-----'*30 +n
                text +=(' '*10)+sc[index]['userName'].encode('utf-8') + '      - 发表于'+ sc[index]['postDate'].encode('utf-8') +'\n' +n
                text +=(' '*10)+del_kr(sc[index]['content'].encode('utf-8'))+'\n' +n
                text +=(' '*10)+'赞 '+sc[index]['likeCountFormat'].encode('utf-8')+ '      - 来自'+ sc[index]['deviceModel'].encode('utf-8') +n
                text +='-----'*30 +n
    text +=('*-'*20)+'最新评论'+('*-'*20) +n
    rc = j['rootComments']
    for index in range(len(rc)):
        text +='-----'*30 +n
        text +=rc[index]['userName'].encode('utf-8') + '      - 发表于'+ rc[index]['postDate'].encode('utf-8') +'\n' +n
        text +=del_kr(rc[index]['content'].encode('utf-8'))+'\n' +n
        text +='赞 '+rc[index]['likeCountFormat'].encode('utf-8')+ '      - 来自'+ rc[index]['deviceModel'].encode('utf-8') +n
        text +='-----'*30
        if str(rc[index]['commentId']) in scm.keys():
            sc = scm[str(rc[index]['commentId'])]['subComments']
            for index in range(len(sc)):
                text +='-----'*30 +n
                text +=(' '*10)+sc[index]['userName'].encode('utf-8') + '      - 发表于'+ sc[index]['postDate'].encode('utf-8') +'\n' +n
                text +=(' '*10)+del_kr(sc[index]['content'].encode('utf-8'))+'\n' +n
                text +=(' '*10)+'赞 '+sc[index]['likeCountFormat'].encode('utf-8')+ '      - 来自'+ sc[index]['deviceModel'].encode('utf-8') +n
                text +='-----'*30 +n
    return text

@plugin.cached(TTL=2)
def get_bangumi(page):
    url = 'https://www.acfun.cn/bangumilist?pageNum=' + str(page)
    videos = []
    rec = requests.get(url,headers=headers)
    soup = BeautifulSoup(rec.text,'html.parser')
    li = soup.find_all('li',class_='ac-mod-li')
    for index in range(len(li)):
        span = li[index].find('span')
        em = li[index].find('em')
        img = li[index].a.div.img['src']
        img = img.split('?')
        videoitem = {}
        videoitem['name'] = span.text + '['+em.text+']'
        videoitem['href'] = plugin.url_for('sources', url=li[index].a['href'])
        videoitem['thumb'] = img[0]
        videos.append(videoitem)
    return videos

@plugin.cached(TTL=2)
def get_videos(category):
#爬视频列表的
    pageurl = category
    r = requests.get(pageurl, headers=headers)
    r.encoding = 'UTF-8'
    rtext= r.text
    j = json.loads(rtext.encode('utf-8'))

    k = j['rankList']
    
    videos = []
    for index in range(len(k)):
            item = k[index]
            videoitem = {}
            videoitem['name'] = item['contentTitle']
            videoitem['href'] = 'https://www.acfun.cn/v/ac' + item['dougaId']
            videoitem['thumb'] = item['coverUrl']
            videoitem['info'] = {'plot':'UP主:' + item['userName'].encode('utf-8') + '\n'}
            videoitem['info']['plot'] += str(item['viewCountShow'].encode('utf-8')) + '播放 · ' + str(item['danmakuCountShow'].encode('utf-8')) + '弹幕 · ' + str(item['commentCountShow'].encode('utf-8')) + '评论\n'
            videoitem['info']['plot'] += 'AC' + str(item['dougaId']) + ' · ' + str(item['bananaCountShow'].encode('utf-8')) + '香蕉\n\n'
            if 'contentDesc' in item:
                videoitem['info']['plot'] += item['contentDesc'].encode('utf-8').replace('<br/>','\n')
            videos.append(videoitem)
    return videos

@plugin.cached(TTL=2)
def get_sources(url):
    #ifmurl = re.match('https://m.acfun.cn',url)
    #if ifmurl != None:
        #url = 'https://www' + url[9:21] + 'ac' + url[25:]
    
    sources = []
    #dialog = xbmcgui.Dialog()
    #ok = dialog.ok('错误提示', url)
    rec = requests.get(url,headers=headers)
    rec.encoding = 'utf-8'
    soup = BeautifulSoup(rec.text, "html5lib")
    if404 = soup.find_all('div', class_='img404')
    
        
        #print(rec.text)
    rectext = rec.text

    cutjson = rectext.encode('utf-8')
    if cutjson.find('window.pageInfo = window.videoInfo = ') != -1:
        str1 = cutjson.find('window.pageInfo = window.videoInfo = ')

        try:
            str2 = cutjson.find('window.videoResource =')
            videoinfo = cutjson[str1+37:str2-10]
            # dialog = xbmcgui.Dialog()
            # dialog.textviewer('错误提示', videoinfo)
            j = json.loads(videoinfo)
            if len(j['videoList']) == 1:
                videosource = {}
                #print('视频标题:')
                videosource['name'] = j['title']
                #print('视频图片:')
                #videosource['thumb'] = '12'
                #print('视频地址:')
                videosource['href'] = plugin.url_for('play', url=url)
                #videosource['category'] = '番剧'
                sources.append(videosource)
                
            else:
                for index in range(len(j['videoList'])):
                    videosource = {}
                    videosource['name'] = j['videoList'][index]['title']
                    videosource['href'] = plugin.url_for('play', url=url + '_' +str(index+1))
                    sources.append(videosource)
                
        except ValueError:
            
            dialog = xbmcgui.Dialog()
            ok = dialog.ok('错误提示', '错误404,咦?世界线变动了,你好像来到了奇怪的地方。看看其他内容吧~')
            
    if cutjson.find('window.pageInfo = window.bangumiData = ') != -1:
        #番剧
        # str1 = cutjson.find('window.bangumiList')
        # str2 = cutjson.find('window.abtestConfig = ')
        bgm = re.search('(?<=window.bangumiList = ).*?(?=;)',cutjson).group()
        
        # bgm = cutjson[str1+21:str2-28]
        j = json.loads(bgm)
        for index in range(len(j['items'])):
            videosource = {}
            videosource['name'] = j['items'][index]['episodeName']
            videosource['href'] = plugin.url_for('play', url=url+uid+str(j['items'][index]['itemId']) + '_' +str(index+1))
            sources.append(videosource)
        #dialog = xbmcgui.Dialog()
        #dialog.textviewer('错误提示',vid)
    return sources


@plugin.route('/sources/<url>/')
def sources(url):
    sources = get_sources(url)
    items = [{
        'label': source['name'],
        'path': source['href'],
        #'thumbnail': source['thumb'],
        #'icon': source['thumb'],
    } for source in sources]
    sorted_items = sorted(items, key=lambda item: item['label'])
    return sorted_items


@plugin.route('/category/<url>/')
def category(url):
    #dialog = xbmcgui.Dialog()
    #ok = dialog.ok('错误提示', url)


    videos = get_videos(url)
    items = [{
        'label': video['name'],
        'path': plugin.url_for('sources', url=video['href']),
	'thumbnail': video['thumb'],
	'icon': video['thumb'],
    'info': video['info'],
    } for video in videos]

    sorted_items = items
    #sorted_items = sorted(items, key=lambda item: item['label'])
    return sorted_items

@plugin.route('/bamgumi/<page>/')
def bangumi(page):
    #dialog = xbmcgui.Dialog()
    #ok = dialog.ok('错误提示', url)

    
    videos = get_bangumi(page)
    
    items = [{
        'label': video['name'],
        'path': video['href'],
	'thumbnail': video['thumb'],
	'icon': video['thumb'],
    } for video in videos]
    num = len(items)
    if num == 42:
        items.append({
        'label': u'[COLOR yellow]下一页[/COLOR]',
        'path': plugin.url_for('bangumi',page=str(int(page)+1)),
    })
    sorted_items = items
    #sorted_items = sorted(items, key=lambda item: item['label'])
    return sorted_items

@plugin.route('/')
def index():
    categories = get_categories()
    items = [{
        'label': category['name'],
        'path': plugin.url_for('category', url=category['link']),
    } for category in categories]
    items.append({
        'label': u'[COLOR yellow]真·番剧[/COLOR]',
        'path': plugin.url_for('bangumi',page=1),
    })
    items.append({
        'label': u'[COLOR yellow]搜索(视频)[/COLOR]',
        'path': plugin.url_for('history',name='输入关键词搜索视频',url='search'),
    })
    items.append({
        'label': u'[COLOR yellow]搜索(番剧)[/COLOR]',
        'path': plugin.url_for('history',name='输入关键词搜索番剧',url='bgmsearch'),
    })
    items.append({
        'label': u'[COLOR yellow]输入ac号[/COLOR]',
        'path': plugin.url_for('history',name='输入ac号',url='ac'),
    })
    return items

@plugin.route('/search/<value>/<page>/')
def search(value,page):
    if value != 'null' and int(page) != 1:
        keyword = value
    else:
        keyboard = xbmc.Keyboard('', '请输入搜索内容')
        xbmc.sleep(1500)
        hi = his['search']
        if value != 'null':
            keyboard.setDefault(value)
        keyboard.doModal()
        if (keyboard.isConfirmed()):
            keyword = keyboard.getText()
            if keyword != '':
                hi[keyword] = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) )
    videos = get_search(keyword, page)
    items = [{
        'label': video['name'],
        'path': plugin.url_for('sources', url=video['href']),
        'thumbnail': video['thumb'],
        'icon': video['thumb']
    } for video in videos]

    
    if len(videos) == 30:
        nextpage = {'label': ' 下一页', 'path': plugin.url_for('search', value=keyword, page=str(int(page)+1))}
        items.append(nextpage)
    return items

@plugin.route('/bgmsearch/<value>/<page>/')
def bgmsearch(value,page):
    if value != 'null' and int(page) != 1:
        keyword = value
    else:
        keyboard = xbmc.Keyboard('', '请输入搜索内容')
        xbmc.sleep(1500)
        hi = his['bgmsearch']
        if value != 'null':
            keyboard.setDefault(value)
        keyboard.doModal()
        if (keyboard.isConfirmed()):
            keyword = keyboard.getText()
            if keyword != '':
                hi[keyword] = str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) )
    videos = get_bgm_search(keyword,page)
    items = [{
        'label': video['name'],
        'path': plugin.url_for('sources', url=video['href']),
        'thumbnail': video['thumb'],
        'icon': video['thumb']
    } for video in videos]
    if len(videos) == 30:
        nextpage = {'label': ' 下一页', 'path': plugin.url_for('bgmsearch', value=keyword, page=str(int(page)+1))}
        items.append(nextpage)
    return items

def get_key (dict, value):
  return [k for k, v in dict.items() if v == value]

@plugin.route('/history/<name>/<url>/')
def history(name,url):
    items = []
    if url == 'search' or url == 'bgmsearch':
        items.append({
            'label': '[COLOR yellow]'+ name +'[/COLOR]',
            'path': plugin.url_for(url,value='null',page=1),
        })
    else:
        items.append({
            'label': '[COLOR yellow]'+ name +'[/COLOR]',
            'path': plugin.url_for(url,value='null'),
        })
    #his[url] ={'aaa':'2019-01-23 10:00:00','bbb':'2019-01-23 09:01:00','ccc':'2019-01-23 09:00:59'}
    if url in his:
        hi = his[url]
        
    else:
        his[url] = {}
        hi = his[url]
        
    #hi = []
    if hi:
        val = list(hi.values())
        val = sorted(val,reverse=True)
        for index in range(len(val)):
            if url == 'search' or url == 'bgmsearch':
                items.append({
                    'label': name+ ':' +get_key(hi,val[index])[0] + ' - [查询时间:' + val[index] +']',
                    'path': plugin.url_for(url,value=get_key(hi,val[index])[0],page=1),
                })
            else:
                items.append({
                    'label': name+ ':' +get_key(hi,val[index])[0] + ' - [查询时间:' + val[index] +']',
                    'path': plugin.url_for(url,value=get_key(hi,val[index])[0]),
                })
        #for index in range(len(hi)):
            #items.append({
                #'label': name+ ':' +hi[index],
                #'path': plugin.url_for(url,value=hi[index]),
            #})
        items.append({
            'label': '[COLOR yellow]清除历史记录[/COLOR]',
            'path': plugin.url_for('cleanhis',url=url),
        })
    else:
        items.append({
            'label': '[COLOR yellow]历史记录为空[/COLOR]',
            'path': plugin.url_for(ok,value='历史记录为空'),
        })

    return items

@plugin.route('/ac/<value>/')
def ac(value):
    if value == 'null':
        keyboard = xbmc.Keyboard('', '请输入ac号:')
        xbmc.sleep(1500)
        keyboard.doModal()

        hi = his['ac']
        if (keyboard.isConfirmed()):
            keyword = keyboard.getText()
            hi[keyword] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 
    else:
        if keyword != '':
            keyword = value
    sources = get_sources('https://www.acfun.cn/v/ac'+str(keyword))
    items = [{
        'label': source['name'],
        'path': source['href'],
        #'thumbnail': source['thumb'],
        #'icon': source['thumb'],
    } for source in sources]
    sorted_items = sorted(items, key=lambda item: item['label'])
    return sorted_items

@plugin.route('/conn/<value>/<st>/')
def conn(value,st):
    text = get_comm(value,st)
    dialog = xbmcgui.Dialog()
    dialog.textviewer('评论区',text)

@plugin.route('/ok/<value>/')
def ok(value):
    dialog = xbmcgui.Dialog()
    ok = dialog.ok('提示', value)

@plugin.route('/cleanhis/<url>/')
def cleanhis(url):
    his[url] = {}
    dialog = xbmcgui.Dialog()
    ok = dialog.ok('提示', '清理历史记录成功')

@plugin.cached(TTL=2)
@plugin.route('/play/<url>/')
def play(url):

    rec = requests.get(url,headers=headers)
    rec.encoding = 'utf-8'
    #print(rec.text)
    rectext = rec.text
    cutjson = rectext.encode('utf-8')
    if cutjson.find('window.pageInfo = window.videoInfo = ') != -1:
        str1 = cutjson.find('window.pageInfo = window.videoInfo = ')
        str2 = cutjson.find('window.videoResource =')
        videoinfo = cutjson[str1+37:str2-10]
        j = json.loads(videoinfo)
        mp4info = {}
        mp4info['title'] = j['title']
        st = '1'
        #简介 plot
        #ac = ac.encode('utf-8')
        uptime = str(j['createTimeMillis'])
        uptime = uptime[:-3]
        uptime = int(uptime)
        #转换成localtime
        time_local = time.localtime(uptime)
        #转换成新的时间格式(2016-05-05 20:28:54)
        uptime = time.strftime("%Y-%m-%d %H:%M:%S",time_local)
        data = time.strftime("%Y-%m-%d",time_local)
        #ac号 显示评论区用
        pinglunqu = j['commentCountShow'].encode('utf-8')
        vid = j['dougaId'].encode('utf-8')

        jianjie =  j['viewCountShow'].encode('utf-8') + '播放 | ' + j['danmakuCountShow'].encode('utf-8') + '弹幕 | ' + j['commentCountShow'].encode('utf-8') +'评论\n'
        jianjie += str(j['likeCount']).encode('utf-8') + '赞 | ' + j['stowCountShow'].encode('utf-8') + '收藏 | ' + j['bananaCountShow'].encode('utf-8')  + '香蕉'
        jianjie += '\n--------------------------\n'
        jianjie += '发布时间:' + uptime +' \nac号:ac' +j['dougaId'].encode('utf-8')
        jianjie += '\n--------------------------\n'
        try:
            mp4info['plot'] = jianjie  + j['description'].encode('utf-8')
        except AttributeError:
            mp4info['plot'] = jianjie 

        #分类 genre	
        genre = [j['channel']['parentName'],j['channel']['name']]
        mp4info['genre'] = genre
    
        #发布时间
        mp4info['aired'] = data
        #up主 cast
        fan = str(j['user']['fanCount'].encode('utf-8')) + '粉丝'
        fan = fan.decode('utf-8')
        mp4info['cast'] = [(j['user']['name'],fan)]
        #tag
        tag = []
        if 'tagList' in j:
            for index in range(len(j['tagList'])):
                tag.append(j['tagList'][index]['name'])
        mp4info['tag'] = tag
        #设置类型
        mp4info['mediatype'] = 'video'
        videojson =j ['currentVideoInfo']['ksPlayJson']
        j2 = json.loads(videojson)
        
        items = []
        if len(j2['adaptationSet'][0]['representation']) == 1:
            title = '['+j2['adaptationSet'][0]['representation'][0]['qualityType'] + ']' + j['title']
            path = j2['adaptationSet'][0]['representation'][0]['url']
            item = {'label': title,'path':path,'is_playable': True,'info':mp4info,'info_type':'video','thumbnail': j['coverCdnUrls'][0]['url'],'icon': j['coverCdnUrls'][0]['url']}
        
            items.append(item)
        #return items
        else:
            for index in range(len(j2['adaptationSet'][0]['representation'])):
                #print(j2['adaptationSet'][0]['representation'][index]['qualityType'])
                #print(j2['adaptationSet'][0]['representation'][index]['url'])
                title = '['+j2['adaptationSet'][0]['representation'][index]['qualityType'] + ']' + j['title']
                path = j2['adaptationSet'][0]['representation'][index]['url']
                item = {'label': title,'path':path,'is_playable': True,'info':mp4info,'info_type':'video','thumbnail': j['coverCdnUrls'][0]['url'],'icon': j['coverCdnUrls'][0]['url']}
        
                items.append(item)
        items.append({
            'label': '[COLOR yellow]查看UP主 [/COLOR]'+j['user']['name'].encode('utf-8')+'[COLOR yellow] 的更多视频[/COLOR]',
            'path': plugin.url_for(up,uid=j['user']['id'],page=1),
        })
    if cutjson.find('window.pageInfo = window.bangumiData = ') != -1:
        #番剧
        str1 = cutjson.find('window.pageInfo = window.bangumiData = ')
        str2 = cutjson.find('window.qualityConfig = ')
        bgm = cutjson[str1+39:str2-10]
        #dialog = xbmcgui.Dialog()
        #dialog.textviewer('错误提示',bgm)
        j = json.loads(bgm)
        bgmjson =j ['currentVideoInfo']['ksPlayJson']
        j2 = json.loads(bgmjson)
        items = []
        mp4info = {}
        mp4info['title'] = j['bangumiTitle']
        st = '2'
        #简介 plot
        #ac = ac.encode('utf-8')
        uptime = str(j['currentVideoInfo']['uploadTime'])
        uptime = uptime[:-3]
        uptime = int(uptime)
        #转换成localtime
        time_local = time.localtime(uptime)
        #转换成新的时间格式(2016-05-05 20:28:54)
        uptime = time.strftime("%Y-%m-%d %H:%M:%S",time_local)
        data = time.strftime("%Y-%m-%d",time_local)


        jianjie =  j['playCountShow'].encode('utf-8') + '播放 | ' + j['currentVideoInfo']['danmakuCountShow'].encode('utf-8') + '弹幕 | ' + j['commentCountShow'].encode('utf-8') +'评论\n'
        jianjie += j['extendsStatus'].encode('utf-8') + ' | ' + j['latestItem'].encode('utf-8') + ' | ' + j['stowCountShow'].encode('utf-8')  + '追番'
        jianjie += '\n--------------------------\n'
        jianjie += '发布时间:' + uptime +' \n链接:' +j['shareUrl'].encode('utf-8')
        jianjie += '\n--------------------------\n'
        try:
            mp4info['plot'] = jianjie  + j['bangumiIntro'].encode('utf-8')
        except AttributeError:
            mp4info['plot'] = jianjie 
        #pinglunqu
        pinglunqu = j['commentCountShow'].encode('utf-8')

        #分类 genre	
        genre = []
        for index in range(len(j['bangumiStyleList'])):
            genre.append(j['bangumiStyleList'][index]['name'])

        mp4info['genre'] = genre
    
        #发布时间
        mp4info['aired'] = data
        #追番人数 cast
        fan = j['stowCountShow'].encode('utf-8') + '追番'
        fan = fan.decode('utf-8')
        mp4info['cast'] = [(j['bangumiTitle'],fan)]
        #tag
        mp4info['tag'] = genre
        #设置类型
        mp4info['mediatype'] = 'video'
        #img
        img = j['bangumiCoverImageV'].split('?')
        img = img[0]
        vid = str(j['bangumiId']).encode('utf-8')
        for index in range(len(j2['adaptationSet'][0]['representation'])):
            #print(j2['adaptationSet'][0]['representation'][index]['qualityType'])
            #print(j2['adaptationSet'][0]['representation'][index]['url'])
            title = '['+j2['adaptationSet'][0]['representation'][index]['qualityType'] + ']' + j['bangumiTitle']
            path = j2['adaptationSet'][0]['representation'][index]['url']
            item = {'label': title,'path':path,'is_playable': True,'info':mp4info,'info_type':'video','thumbnail': img,'icon': img}
        
            items.append(item)
    items.append({
        'label': '[COLOR yellow]评论区[/COLOR]  '+str(pinglunqu),
        'path': plugin.url_for(conn,value=vid,st=st),
    })
    
    
    #dialog = xbmcgui.Dialog()
    #dialog.textviewer('评论区',st)
    return items
     
@plugin.route('/up/<uid>/<page>/')
def up(uid,page):
    videos = get_up(uid,page)
    items = [{
        'label': video['name'],
        'path': plugin.url_for('sources', url=video['href']),
	'thumbnail': video['thumb'],
	'icon': video['thumb'],
    } for video in videos]
    if len(videos) == 20:
        items.append({
            'label': '[COLOR yellow]下一页[/COLOR]  ',
            'path': plugin.url_for(up,uid=uid,page=int(page)+1),
        })
    
    
    return items

@plugin.route('/labels/<label>/')
def show_label(label):
    # 写抓取视频类表的方法
    #
    items = [
        {'label': label},
    ]
    return items

if __name__ == '__main__':
    plugin.run()


================================================
FILE: plugin.video.acfun/addon.xml
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.acfun" name="Acfun" version="0.2.3" provider-name="zhengfan">
  <requires>
    <import addon="xbmc.python" version="2.1.0"/>
    <import addon="script.module.xbmcswift2" version="2.4.0"/>
  <import addon="script.module.beautifulsoup4" version="4.5.3"/>
  <import addon="script.module.requests" version="2.19.1"/>
  <import addon="script.module.html5lib" version="0.999.0"/>
  </requires>
  <extension point="xbmc.python.pluginsource" library="addon.py">
    <provides>video</provides>
  </extension>
  <extension point="xbmc.addon.metadata">
    <platform>all</platform>
    <language></language>
    <description>AcFun是一家弹幕视频网站,致力于为每一个人带来欢乐。</description>
  </extension>
</addon>


================================================
FILE: plugin.video.acfun/readme.md
================================================
# acfun for kodi 0.2.1
## 简介
- AcFun是一家弹幕视频网站,致力于为每一个人带来欢乐
## 主要功能
> - [x] 视频分类
> - [x] 在线播放1080p视频
> - [x] 使用官方api解析视频
> - [x] 在线播放番剧
> - [x] 搜索功能(使用官方搜索api)
> - [x] 按ac号访问视频功能
> - [x] 缓存功能(减少向服务器请求次数)
> - [ ] 实现显示弹幕功能
## 更新历史
 > -[v0.1.1]----------------------  
 > 修复 - 多p视频无法正常显示,解析,播放  
 > -[v0.1.0]----------------------  
 > 发布 - 首个版本  



================================================
FILE: plugin.video.acfun/resources/__init__.py
================================================


================================================
FILE: plugin.video.acfun/resources/language/English/strings.xml
================================================
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
  <!-- Plugin name -->
  <string id="30000">bilibili</string>
</strings>


================================================
FILE: plugin.video.acfun/resources/lib/__init__.py
================================================


================================================
FILE: plugin.video.bangumi/addon.py
================================================
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from xbmcswift2 import Plugin,xbmcaddon,xbmc
import requests
from bs4 import BeautifulSoup
import xbmcgui
import time
import base64
import json
import urllib2
import sys
import HTMLParser
import re
import cfscrape
import random
import os

__addon__      = xbmcaddon.Addon()
__author__     = __addon__.getAddonInfo('author')
__scriptid__   = __addon__.getAddonInfo('id')
__scriptname__ = __addon__.getAddonInfo('name')
__version__    = __addon__.getAddonInfo('version')
__language__   = __addon__.getLocalizedString

__cwd__        = xbmc.translatePath( __addon__.getAddonInfo('path') ).decode("utf-8")
__profile__    = xbmc.translatePath( __addon__.getAddonInfo('profile') ).decode("utf-8")
__resource__   = xbmc.translatePath( os.path.join( __cwd__, 'resources', 'lib' ) ).decode("utf-8")
__temp__       = xbmc.translatePath( os.path.join( __profile__, 'temp') ).decode("utf-8")

sys.path.append (__resource__)
# from zhconv import convert


def unescape(string):
    string = urllib2.unquote(string).decode('utf8')
    quoted = HTMLParser.HTMLParser().unescape(string).encode('utf-8')
    #转成中文
    return re.sub(r'%u([a-fA-F0-9]{4}|[a-fA-F0-9]{2})', lambda m: unichr(int(m.group(1), 16)), quoted)

def sat(word,fanyi='zh-hans',sub=''):
    if type(word) == str:
        word = word.decode('utf-8')
    if sub != '':
        sub = eval(sub)
        for key in sub:
            word = word.replace(key.decode('utf-8'),sub[key].decode('utf-8'))
    word = convert(word,fanyi)
    return word.encode('utf-8')

plugin = Plugin()

macheaders = {'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4 Supplemental Update) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15'}
ipadheaders = {'user-agent': 'Mozilla/5.0 (iPad; CPU OS 10_15_4 Supplemental Update like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Mobile/15E148 Safari/605.1.15'}
iphoneheaders = {'user-agent': 'Mozilla/5.0 (iPhone; CPU OS 10_15_4 Supplemental Update like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Mobile/14E304 Safari/605.1.15'}
mheaders = {'user-agent':'Mozilla/5.0 (Linux; Android 10; Z832 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Mobile Safari/537.36'}
headers = {'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'}
tmp = plugin.get_storage('tmp')

#用户设置存储
storage = plugin.get_storage('storage')
#搜索历史纪录
his = plugin.get_storage('his')


def chushihua(key,default):
    if key in storage:
        switch = storage[key]
    else:
        storage[key] = default
        switch = storage[key]
    if switch == 1:
        value = '开'
    else:
        value = '关'
    return value

@plugin.cached(TTL=2)
def get_html(url,ua='pc',cf='',mode='html',encode='utf-8'):
    if cf == '':
        if ua == 'pc':
            r = requests.get(url,headers=headers)
        if ua == 'mobile':
            r = requests.get(url,headers=mheaders)
        if ua == 'iphone':
            r = requests.get(url,headers=iphoneheaders)
        if ua == 'ipad':
            r = requests.get(url,headers=ipadheaders)
        if ua == 'mac':
            r = requests.get(url,headers=macheaders)
        if encode == 'utf-8':
            r.encoding = 'utf-8'
        if encode == 'gbk':
            r.encoding = 'gbk'
        if mode == 'url':
            html = r.url
        else:
            html = r.text
    else:
        scraper = cfscrape.create_scraper()
        if ua == 'pc':
            s = scraper.get_tokens(url,headers=headers)
            r = requests.get(url,headers=headers,cookies=s[0])
        if ua == 'mobile':
            s = scraper.get_tokens(url,headers=mheaders)
            r = requests.get(url,headers=mheaders,cookies=s[0])
        if ua == 'iphone':
            s = scraper.get_tokens(url,headers=iphoneheaders)
            r = requests.get(url,headers=iphoneheaders,cookies=s[0])
        if ua == 'ipad':
            s = scraper.get_tokens(url,headers=ipadheaders)
            r = requests.get(url,headers=ipadheaders,cookies=s[0])
        if ua == 'mac':
            s = scraper.get_tokens(url,headers=macheaders)
            r = requests.get(url,headers=macheaders,cookies=s[0])

        if encode == 'utf-8':
            r.encoding = 'utf-8'
        if encode == 'gbk':
            r.encoding = 'gbk'

        if mode == 'url':
            html = r.url
        else:
            html = r.text
    return html

@plugin.cached(TTL=2)
def post_html(url,data,ua='pc',cf='',encode='utf-8'):
    data =eval(data)
    if cf == '':
        if ua == 'pc':
            r = requests.post(url,headers=headers,data=data)
        if ua == 'mobile':
            r = requests.post(url,headers=mheaders,data=data)
        if ua == 'iphone':
            r = requests.post(url,headers=iphoneheaders,data=data)
        if ua == 'ipad':
            r = requests.post(url,headers=ipadheaders,data=data)
        if ua == 'mac':
            r = requests.post(url,headers=macheaders,data=data)
        
        if encode == 'utf-8':
            r.encoding = 'utf-8'
        if encode == 'gbk':
            r.encoding = 'gbk'
        html = r.text
    else:
        scraper = cfscrape.create_scraper()
        html = scraper.post(url,data).content
    return html

def unix_to_data(uptime,format='data'):
    if len(str(uptime)) > 10:
        uptime = str(uptime)[:-(len(str(uptime))-10)]
    uptime = float(uptime)
    time_local = time.localtime(uptime)
    if format == 'data' or format == 'zhdata' or format == 'datatime' or format == 'zhdatatime' or format == 'time' or format == 'zhtime':
        if format == 'data':
            uptime = time.strftime('%Y-%m-%d',time_local)
        if format == 'zhdata':
            uptime = time.strftime('%Y年%m月%d日',time_local)
        if format == 'datatime':
            uptime = time.strftime('%Y-%m-%d %H:%M:%S',time_local)
        if format == 'zhdatatime':
            uptime = time.strftime('%Y年%m月%d日 %H时%M分%S秒',time_local)
        if format == 'time':
            uptime = time.strftime('%H:%M:%S',time_local)
        if format == 'zhtime':
            uptime = time.strftime('%H时%M分%S秒',time_local)
    else:
        uptime = time.strftime(format,time_local)
    return uptime

def tiqu_num(string):
    try:
        a = re.search('\d+',string).group()
        return a
    except AttributeError:
        return ''

def get_categories_mode(mode):
    item = eval('get_' + mode + '_categories')()
    return item
def get_videos_mode(url,mode,page):
    item = eval('get_' + mode + '_videos')(url,page)
    return item
def get_source_mode(url,mode):
    item = eval('get_' + mode + '_source')(url)
    return item
def get_mp4info_mode(url,mode):
    item = eval('get_' + mode + '_mp4info')(url)
    return item
def get_mp4_mode(url,mode):
    item = eval('get_' + mode + '_mp4')(url)
    return item
def get_search_mode(keyword,page,mode):
    item = eval('get_' + mode + '_search')(keyword,page)
    return item

damakulist = ['bimibimi','yhdm','agefans','silisili','iafuns','qinmei','srsg','ningmoe']
##########################################################
###主入口
##########################################################

def get_categories():
    return [{'id':1,'name':'哔咪哔咪(bimibimi.tv)[COLOR pink][/COLOR]','link':'bimibimi','author':'zhengfan2014','upload':'2020-6-26','videos':24,'search':24,'plot':'更新速度比樱花稍慢,但是总体画质比樱花高'},
            {'id':2,'name':'樱花动漫(yhdm.io)','link':'yhdm','author':'zhengfan2014','upload':'2020-6-26','videos':15,'search':20,'plot':'昨晚b站23点发布的BNA,今天早上就可以在樱花看了,更新速度杠杠滴'},
            {'id':3,'name':'Age动漫(agefans.tw)','link':'agefans','aut
Download .txt
gitextract_lwjw29km/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── ------.md
│   │   ├── -----.md
│   │   ├── ----.md
│   │   └── feature_request.md
│   ├── auto.py
│   └── workflows/
│       └── auto.yml
├── LICENSE
├── README.md
├── addons.xml
├── addons.xml.md5
├── metadata.douban.com.python/
│   ├── LICENSE.txt
│   ├── README.md
│   ├── addon.xml
│   ├── python/
│   │   ├── lib/
│   │   │   ├── __init__.py
│   │   │   └── tmdbscraper/
│   │   │       ├── __init__.py
│   │   │       ├── api_utils.py
│   │   │       ├── fanarttv.py
│   │   │       ├── imdbratings.py
│   │   │       ├── tmdb.py
│   │   │       ├── tmdbapi.py
│   │   │       └── traktratings.py
│   │   ├── scraper.py
│   │   ├── scraper_config.py
│   │   └── scraper_datahelper.py
│   └── resources/
│       ├── language/
│       │   └── Chinese (Simple)/
│       │       └── strings.po
│       └── settings.xml
├── plugin.audio.jsososo/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   ├── Chinese (Simple)/
│       │   │   └── strings.po
│       │   └── English/
│       │       └── strings.xml
│       ├── lib/
│       │   └── __init__.py
│       └── settings.xml
├── plugin.video.acfun/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.bangumi/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           ├── __init__.py
│           ├── zhcdict.json
│           └── zhconv.py
├── plugin.video.bilibili/
│   ├── addon.py
│   ├── addon.xml
│   ├── danmuku.py
│   ├── readme.md
│   ├── resources/
│   │   ├── __init__.py
│   │   ├── language/
│   │   │   ├── Chinese (Simple)/
│   │   │   │   └── strings.po
│   │   │   ├── English/
│   │   │   │   └── strings.xml
│   │   │   ├── resource.language.en_us/
│   │   │   │   └── strings.po
│   │   │   └── resource.language.zh_cn/
│   │   │       └── strings.po
│   │   ├── lib/
│   │   │   └── __init__.py
│   │   └── settings.xml
│   └── xml2ass.py
├── plugin.video.bimibimi[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.changku/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.cine/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.clicli[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.huanxi/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.kaiyan/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.medicalvideo/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.pengpai[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.reallive/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.skypixel/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.taptap/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.vid/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.weibotv/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.xigua[停止更新]/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── plugin.video.xinpianchang/
│   ├── addon.py
│   ├── addon.xml
│   ├── readme.md
│   └── resources/
│       ├── __init__.py
│       ├── language/
│       │   └── English/
│       │       └── strings.xml
│       └── lib/
│           └── __init__.py
├── service.subtitles.acfun/
│   ├── addon.xml
│   ├── readme.md
│   ├── resources/
│   │   └── lib/
│   │       ├── __init__.py
│   │       └── xml2ass.py
│   └── service.py
├── service.subtitles.bilibili/
│   ├── addon.xml
│   ├── readme.md
│   ├── resources/
│   │   └── lib/
│   │       ├── __init__.py
│   │       └── xml2ass.py
│   └── service.py
└── step1/
    ├── README.MD
    ├── acfun-rank-list.py
    ├── acfun-video.py
    ├── bangumi.py
    ├── bilibili-all-list.py
    ├── bilibili-bangumi-list.py
    ├── bilibili-rank-list.py
    ├── bilibili-video-api.py
    ├── bilibili-video-list.py
    ├── kaiyan.py
    ├── livideo.py
    ├── pengpai.py
    ├── taptap.py
    ├── weibo.py
    ├── weibomiaopai的js加密算法破解.py
    ├── 医学卫视.py
    ├── 国土公开课.py
    └── 新片场和场库.py
Download .txt
SYMBOL INDEX (833 symbols across 36 files)

FILE: metadata.douban.com.python/python/lib/tmdbscraper/__init__.py
  function get_imdb_id (line 2) | def get_imdb_id(uniqueids):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/api_utils.py
  function set_headers (line 41) | def set_headers(headers):
  function load_info (line 45) | def load_info(url, params=None, default=None, resp_type = 'json'):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/fanarttv.py
  function get_details (line 22) | def get_details(uniqueids, clientkey, language, set_tmdbid):
  function _get_mediaid (line 45) | def _get_mediaid(uniqueids):
  function _get_data (line 50) | def _get_data(media_id, clientkey):
  function _parse_data (line 58) | def _parse_data(data, language):
  function _get_imagelanguage (line 80) | def _get_imagelanguage(arttype, image):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/imdbratings.py
  function get_details (line 30) | def get_details(uniqueids):
  function _get_ratinginfo (line 37) | def _get_ratinginfo(imdb_id):
  function _assemble_imdb_result (line 41) | def _assemble_imdb_result(votes, rating, top250):
  function _parse_imdb_result (line 49) | def _parse_imdb_result(input_html):
  function _parse_imdb_rating (line 56) | def _parse_imdb_rating(input_html):
  function _parse_imdb_votes (line 62) | def _parse_imdb_votes(input_html):
  function _parse_imdb_top250 (line 68) | def _parse_imdb_top250(input_html):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/tmdb.py
  class TMDBMovieScraper (line 5) | class TMDBMovieScraper(object):
    method __init__ (line 6) | def __init__(self, url_settings, language, certification_country):
    method urls (line 13) | def urls(self):
    method search (line 18) | def search(self, title, year=None):
    method get_details (line 55) | def get_details(self, uniqueids):
    method _gather_details (line 64) | def _gather_details(self, media_id):
    method _assemble_details (line 80) | def _assemble_details(self, movie, movie_fallback, collection, collect...
  function _parse_media_id (line 130) | def _parse_media_id(title):
  function _get_movie (line 140) | def _get_movie(mid, language=None, search=False):
  function _get_moviecollection (line 151) | def _get_moviecollection(collection_id, language=None):
  function _parse_artwork (line 162) | def _parse_artwork(movie, collection, urlbases, language):
  function _get_images_with_fallback (line 185) | def _get_images_with_fallback(imagelist, urlbases, language, language_fa...
  function _get_images (line 198) | def _get_images(imagelist, urlbases, language='_any'):
  function _get_date_numeric (line 209) | def _get_date_numeric(datetime_):
  function _load_base_urls (line 212) | def _load_base_urls(url_settings):
  function _parse_trailer (line 228) | def _parse_trailer(trailers, fallback):
  function _get_names (line 235) | def _get_names(items):
  function _get_cast_members (line 238) | def _get_cast_members(casts, casttype, department, jobs):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/tmdbapi.py
  function search_movie (line 45) | def search_movie(query, year=None, language=None):
  function find_movie_by_external_id (line 64) | def find_movie_by_external_id(external_id, language=None):
  function get_movie (line 81) | def get_movie(mid, language=None, append_to_response=None):
  function get_collection (line 96) | def get_collection(collection_id, language=None, append_to_response=None):
  function get_configuration (line 111) | def get_configuration():
  function _set_params (line 122) | def _set_params(append_to_response, language):

FILE: metadata.douban.com.python/python/lib/tmdbscraper/traktratings.py
  function get_trakt_ratinginfo (line 44) | def get_trakt_ratinginfo(uniqueids):

FILE: metadata.douban.com.python/python/scraper.py
  function log (line 29) | def log(msg, level=xbmc.LOGDEBUG):
  function get_html (line 46) | def get_html(url, ua='pc', cookie='', mode='html', encode='utf-8'):
  function get_douban_videourl (line 101) | def get_douban_videourl(url):
  function get_douban_imglist (line 118) | def get_douban_imglist(url):
  function get_douban_search (line 164) | def get_douban_search(title, year):
  function get_douban_details (line 182) | def get_douban_details(input_uniqueids):
  function get_tmdb_scraper (line 313) | def get_tmdb_scraper(settings):
  function search_for_movie (line 322) | def search_for_movie(title, year, handle, settings):
  function _strip_trailing_article (line 352) | def _strip_trailing_article(title):
  function _searchresult_to_listitem (line 360) | def _searchresult_to_listitem(movie):
  function add_artworks (line 387) | def add_artworks(listitem, artworks):
  function get_details (line 399) | def get_details(input_uniqueids, handle, settings):
  function find_uniqueids_in_nfo (line 463) | def find_uniqueids_in_nfo(nfo, handle):
  function build_lookup_string (line 471) | def build_lookup_string(uniqueids):
  function parse_lookup_string (line 475) | def parse_lookup_string(uniqueids):
  function run (line 484) | def run():

FILE: metadata.douban.com.python/python/scraper_config.py
  function configure_scraped_details (line 1) | def configure_scraped_details(details, settings):
  function configure_tmdb_artwork (line 10) | def configure_tmdb_artwork(details, settings):
  function is_fanarttv_configured (line 33) | def is_fanarttv_configured(settings):
  function _configure_rating_prefix (line 36) | def _configure_rating_prefix(details, settings):
  function _configure_keeporiginaltitle (line 41) | def _configure_keeporiginaltitle(details, settings):
  function _configure_trailer (line 46) | def _configure_trailer(details, settings):
  function _configure_multiple_studios (line 51) | def _configure_multiple_studios(details, settings):
  function _configure_default_rating (line 56) | def _configure_default_rating(details, settings):
  function _configure_tags (line 70) | def _configure_tags(details, settings):
  class PathSpecificSettings (line 82) | class PathSpecificSettings(object):
    method __init__ (line 84) | def __init__(self, settings_dict, log_fn):
    method getSettingBool (line 88) | def getSettingBool(self, id):
    method getSettingInt (line 91) | def getSettingInt(self, id):
    method getSettingNumber (line 94) | def getSettingNumber(self, id):
    method getSettingString (line 97) | def getSettingString(self, id):
    method _inner_get_setting (line 100) | def _inner_get_setting(self, setting_id, setting_type, default):
    method _log_bad_value (line 107) | def _log_bad_value(self, value, setting_id):

FILE: metadata.douban.com.python/python/scraper_datahelper.py
  function get_params (line 8) | def get_params(argv):
  function combine_scraped_details_info_and_ratings (line 16) | def combine_scraped_details_info_and_ratings(original_details, additiona...
  function combine_scraped_details_available_artwork (line 30) | def combine_scraped_details_available_artwork(original_details, addition...
  function find_uniqueids_in_text (line 42) | def find_uniqueids_in_text(input_text):

FILE: plugin.audio.jsososo/addon.py
  function unix_to_data (line 17) | def unix_to_data(uptime,format='data'):
  function zh (line 40) | def zh(num):
  function get_real_url (line 52) | def get_real_url(url):
  function unescape (line 56) | def unescape(string):
  function get_html (line 87) | def get_html(url,cookie=''):
  function one63weinituijian (line 97) | def one63weinituijian():
  function qqweinituijian (line 120) | def qqweinituijian():
  function one63ritui (line 135) | def one63ritui():
  function qqritui (line 177) | def qqritui():
  function one63gedan (line 207) | def one63gedan():
  function qqgedan (line 225) | def qqgedan():
  function one63tuijiangedan (line 242) | def one63tuijiangedan():
  function qqtuijiangedan (line 257) | def qqtuijiangedan():
  function one63playlist (line 273) | def one63playlist(id):
  function qqplaylist (line 318) | def qqplaylist(id):
  function one63album (line 345) | def one63album(id):
  function qqalbum (line 377) | def qqalbum(id):
  function one63singer (line 403) | def one63singer(id):
  function qqsinger (line 419) | def qqsinger(id):
  function get_rank (line 444) | def get_rank():
  function one63rank (line 472) | def one63rank(value):
  function qqrank (line 506) | def qqrank(value):
  function one63mvlist (line 545) | def one63mvlist(page):
  function qqmvlist (line 558) | def qqmvlist(page):
  function one63playmv (line 571) | def one63playmv(vid):
  function qqplaymv (line 577) | def qqplaymv(vid):
  function one63mvinfo (line 583) | def one63mvinfo(vid):
  function qqmvinfo (line 602) | def qqmvinfo(vid):
  function one63search (line 621) | def one63search(keyword,type,page):
  function qqsearch (line 731) | def qqsearch(keyword,type,page):
  function one63playvideo (line 795) | def one63playvideo(vid):
  function one63videoinfo (line 801) | def one63videoinfo(vid):
  function index (line 824) | def index():
  function tuijian (line 857) | def tuijian():
  function ritui (line 870) | def ritui():
  function mv (line 890) | def mv():
  function so (line 903) | def so():
  function gedang (line 964) | def gedang():
  function rank (line 983) | def rank():
  function ranklist (line 996) | def ranklist(value):
  function get_mv (line 1022) | def get_mv(mode,page):
  function get_tuijian (line 1042) | def get_tuijian(mode):
  function get_ritui (line 1062) | def get_ritui(mode):
  function rituilist (line 1095) | def rituilist(mode):
  function get_gedang (line 1114) | def get_gedang(mode):
  function playlist (line 1135) | def playlist(url):
  function playmv (line 1168) | def playmv(url):
  function playvideo (line 1205) | def playvideo(url):
  function playalbum (line 1235) | def playalbum(url):
  function playsinger (line 1267) | def playsinger(url):
  function show_label (line 1299) | def show_label(label):
  function input (line 1365) | def input(key,value):
  function search (line 1379) | def search(value,page,type,mode):
  function get_key (line 1476) | def get_key (dict, value):
  function history (line 1480) | def history(name,url,type,mode):
  function ok (line 1516) | def ok(value):
  function cleanhis (line 1521) | def cleanhis(url):

FILE: plugin.video.acfun/addon.py
  function unescape (line 18) | def unescape(string):
  function del_kr (line 33) | def del_kr(txt):
  function get_categories (line 44) | def get_categories():
  function get_search (line 59) | def get_search(keyword, page):
  function get_bgm_search (line 84) | def get_bgm_search(keyword,page):
  function get_up (line 108) | def get_up(uid,page):
  function get_comm (line 130) | def get_comm(val,st):
  function get_bangumi (line 174) | def get_bangumi(page):
  function get_videos (line 193) | def get_videos(category):
  function get_sources (line 219) | def get_sources(url):
  function sources (line 288) | def sources(url):
  function category (line 301) | def category(url):
  function bangumi (line 320) | def bangumi(page):
  function index (line 344) | def index():
  function search (line 369) | def search(value,page):
  function bgmsearch (line 398) | def bgmsearch(value,page):
  function get_key (line 424) | def get_key (dict, value):
  function history (line 428) | def history(name,url):
  function ac (line 481) | def ac(value):
  function conn (line 505) | def conn(value,st):
  function ok (line 511) | def ok(value):
  function cleanhis (line 516) | def cleanhis(url):
  function play (line 523) | def play(url):
  function up (line 682) | def up(uid,page):
  function show_label (line 700) | def show_label(label):

FILE: plugin.video.bangumi/addon.py
  function unescape (line 35) | def unescape(string):
  function sat (line 41) | def sat(word,fanyi='zh-hans',sub=''):
  function chushihua (line 66) | def chushihua(key,default):
  function get_html (line 79) | def get_html(url,ua='pc',cf='',mode='html',encode='utf-8'):
  function post_html (line 129) | def post_html(url,data,ua='pc',cf='',encode='utf-8'):
  function unix_to_data (line 153) | def unix_to_data(uptime,format='data'):
  function tiqu_num (line 175) | def tiqu_num(string):
  function get_categories_mode (line 182) | def get_categories_mode(mode):
  function get_videos_mode (line 185) | def get_videos_mode(url,mode,page):
  function get_source_mode (line 188) | def get_source_mode(url,mode):
  function get_mp4info_mode (line 191) | def get_mp4info_mode(url,mode):
  function get_mp4_mode (line 194) | def get_mp4_mode(url,mode):
  function get_search_mode (line 197) | def get_search_mode(keyword,page,mode):
  function get_categories (line 206) | def get_categories():
  function get_bimibimi_categories (line 227) | def get_bimibimi_categories():
  function get_bimibimi_videos (line 234) | def get_bimibimi_videos(url,page):
  function get_bimibimi_source (line 253) | def get_bimibimi_source(url):
  function get_bimibimi_mp4info (line 274) | def get_bimibimi_mp4info(url):
  function get_bimibimi_mp4 (line 314) | def get_bimibimi_mp4(url):
  function get_bimibimi_search (line 344) | def get_bimibimi_search(keyword,page):
  function get_yhdm_categories (line 368) | def get_yhdm_categories():
  function get_yhdm_videos (line 378) | def get_yhdm_videos(url,page):
  function get_yhdm_source (line 401) | def get_yhdm_source(url):
  function get_yhdm_mp4info (line 425) | def get_yhdm_mp4info(url):
  function get_yhdm_mp4 (line 449) | def get_yhdm_mp4(url):
  function get_yhdm_search (line 476) | def get_yhdm_search(keyword,page):
  function get_agefans_categories (line 498) | def get_agefans_categories():
  function get_agefans_videos (line 502) | def get_agefans_videos(url,page):
  function get_agefans_source (line 525) | def get_agefans_source(url):
  function get_agefans_mp4info (line 557) | def get_agefans_mp4info(url):
  function get_agefans_mp4 (line 603) | def get_agefans_mp4(url):
  function get_agefans_search (line 631) | def get_agefans_search(keyword,page):
  function get_qinmei_categories (line 659) | def get_qinmei_categories():
  function get_qinmei_videos (line 669) | def get_qinmei_videos(url,page):
  function get_qinmei_source (line 689) | def get_qinmei_source(url):
  function get_qinmei_mp4info (line 709) | def get_qinmei_mp4info(url):
  function get_qinmei_mp4 (line 753) | def get_qinmei_mp4(url):
  function get_qinmei_search (line 761) | def get_qinmei_search(keyword,page):
  function get_ningmoe_categories (line 783) | def get_ningmoe_categories():
  function get_ningmoe_videos (line 791) | def get_ningmoe_videos(url,page):
  function get_ningmoe_source (line 824) | def get_ningmoe_source(url):
  function get_ningmoe_mp4info (line 853) | def get_ningmoe_mp4info(url):
  function get_ningmoe_mp4 (line 869) | def get_ningmoe_mp4(url):
  function get_ningmoe_search (line 884) | def get_ningmoe_search(keyword,page):
  function get_iafuns_categories (line 905) | def get_iafuns_categories():
  function get_iafuns_videos (line 909) | def get_iafuns_videos(url,page):
  function get_iafuns_source (line 923) | def get_iafuns_source(url):
  function get_iafuns_mp4info (line 951) | def get_iafuns_mp4info(url):
  function get_iafuns_mp4 (line 986) | def get_iafuns_mp4(url):
  function get_iafuns_search (line 1019) | def get_iafuns_search(keyword,page):
  function get_silisili_categories (line 1035) | def get_silisili_categories():
  function get_silisili_videos (line 1040) | def get_silisili_videos(url,page):
  function get_silisili_source (line 1069) | def get_silisili_source(url):
  function get_silisili_mp4info (line 1089) | def get_silisili_mp4info(url):
  function get_silisili_mp4 (line 1130) | def get_silisili_mp4(url):
  function get_silisili_search (line 1146) | def get_silisili_search(keyword,page):
  function get_srsg_categories (line 1174) | def get_srsg_categories():
  function get_srsg_videos (line 1178) | def get_srsg_videos(url,page):
  function get_srsg_source (line 1209) | def get_srsg_source(url):
  function get_srsg_mp4info (line 1238) | def get_srsg_mp4info(url):
  function get_srsg_mp4 (line 1258) | def get_srsg_mp4(url):
  function get_tucao_categories (line 1265) | def get_tucao_categories():
  function get_tucao_videos (line 1270) | def get_tucao_videos(url,page):
  function get_tucao_source (line 1289) | def get_tucao_source(url):
  function get_tucao_mp4info (line 1331) | def get_tucao_mp4info(url):
  function get_tucao_mp4 (line 1343) | def get_tucao_mp4(url):
  function get_tucao_search (line 1347) | def get_tucao_search(keyword,page):
  function get_cliclime_categories (line 1367) | def get_cliclime_categories():
  function get_cliclime_videos (line 1373) | def get_cliclime_videos(url,page):
  function get_cliclime_source (line 1399) | def get_cliclime_source(url):
  function get_cliclime_mp4info (line 1438) | def get_cliclime_mp4info(url):
  function get_cliclime_mp4 (line 1454) | def get_cliclime_mp4(url):
  function get_cliclime_search (line 1467) | def get_cliclime_search(keyword,page):
  function get_5dmtv_categories (line 1493) | def get_5dmtv_categories():
  function get_5dmtv_videos (line 1499) | def get_5dmtv_videos(url,page):
  function get_5dmtv_source (line 1524) | def get_5dmtv_source(url):
  function get_5dmtv_mp4info (line 1550) | def get_5dmtv_mp4info(url):
  function get_5dmtv_mp4 (line 1571) | def get_5dmtv_mp4(url):
  function get_cliclico_categories (line 1594) | def get_cliclico_categories():
  function get_cliclico_videos (line 1600) | def get_cliclico_videos(url,page):
  function get_cliclico_source (line 1616) | def get_cliclico_source(url):
  function get_cliclico_mp4 (line 1645) | def get_cliclico_mp4(url):
  function get_cliclico_search (line 1651) | def get_cliclico_search(keyword,page):
  function zzzfun_fuckddos (line 1668) | def zzzfun_fuckddos(url):
  function get_zzzfun_categories (line 1681) | def get_zzzfun_categories():
  function get_zzzfun_videos (line 1687) | def get_zzzfun_videos(url,page):
  function get_zzzfun_source (line 1708) | def get_zzzfun_source(url):
  function get_zzzfun_mp4info (line 1733) | def get_zzzfun_mp4info(url):
  function get_zzzfun_mp4 (line 1759) | def get_zzzfun_mp4(url):
  function get_zzzfun_search (line 1774) | def get_zzzfun_search(keyword,page):
  function dmd8_fuckddos (line 1798) | def dmd8_fuckddos(url,data=''):
  function get_dmd8_categories (line 1816) | def get_dmd8_categories():
  function get_dmd8_videos (line 1822) | def get_dmd8_videos(url,page):
  function get_dmd8_source (line 1841) | def get_dmd8_source(url):
  function get_dmd8_mp4 (line 1891) | def get_dmd8_mp4(url):
  function get_dmd8_search (line 1916) | def get_dmd8_search(keyword,page):
  function play (line 1944) | def play(name,url,mode):
  function hannum (line 1958) | def hannum(x):
  function diff (line 1965) | def diff(listA,listB):
  function duop (line 1970) | def duop(name,list,mode):
  function source (line 1986) | def source(name,url,img,mode):
  function category (line 2001) | def category(name,url,mode,page):
  function home (line 2035) | def home(mode):
  function search (line 2052) | def search(value,page,mode):
  function get_key (line 2094) | def get_key (dict, value):
  function history (line 2098) | def history(name,url,mode):
  function ok (line 2134) | def ok(value):
  function cleanhis (line 2139) | def cleanhis(url):
  function index (line 2145) | def index():
  function setting (line 2234) | def setting():
  function homesort (line 2255) | def homesort():
  function homeedit (line 2276) | def homeedit(value):
  function keyword (line 2289) | def keyword(key,name):
  function keywordxad (line 2314) | def keywordxad(key,value,mode):
  function switch (line 2366) | def switch(key):
  function show_label (line 2378) | def show_label(label):

FILE: plugin.video.bangumi/resources/lib/zhconv.py
  function loaddict (line 68) | def loaddict(filename=DICTIONARY):
  function getdict (line 83) | def getdict(locale):
  function getpfset (line 129) | def getpfset(convdict):
  function issimp (line 136) | def issimp(s, full=False):
  function fallback (line 170) | def fallback(locale, mapping):
  function convtable2dict (line 176) | def convtable2dict(convtable, locale, update=None):
  function tokenize (line 198) | def tokenize(s, locale, update=None):
  function convert (line 235) | def convert(s, locale, update=None):
  function convert_for_mw (line 292) | def convert_for_mw(s, locale, update=None):
  function test_convert_mw (line 427) | def test_convert_mw(locale, update=None):
  function main (line 449) | def main():

FILE: plugin.video.bilibili/addon.py
  function random_sentence (line 33) | def random_sentence(size):
  function unescape (line 38) | def unescape(string):
  function zh (line 55) | def zh(num):
  function bp (line 69) | def bp(li):
  function rd_live_gz (line 90) | def rd_live_gz():
  function two_one (line 97) | def two_one(tid):
  function level_color (line 161) | def level_color(level):
  function sessdata (line 179) | def sessdata(mode=''):
  function uid (line 192) | def uid():
  function get_html (line 197) | def get_html(url, t=1, debug='no', head=''):
  function get_html_1hour (line 227) | def get_html_1hour(url, head=''):
  function get_html_10min (line 238) | def get_html_10min(url, head=''):
  function get_html_1min (line 249) | def get_html_1min(url, head=''):
  function get_up_roomold (line 259) | def get_up_roomold(uid):
  function get_up_baseinfo (line 268) | def get_up_baseinfo(uid):
  function get_upinfo (line 273) | def get_upinfo(uid):
  function up_sort_vid (line 371) | def up_sort_vid(uid, sort):
  function up_allnum (line 382) | def up_allnum(uid):
  function get_search (line 413) | def get_search(keyword, page):
  function get_vidsearch (line 492) | def get_vidsearch(keyword, page):
  function get_bgsearch (line 547) | def get_bgsearch(keyword, page):
  function get_movsearch (line 597) | def get_movsearch(keyword, page):
  function get_livesearch (line 647) | def get_livesearch(keyword, page):
  function get_upsearch (line 692) | def get_upsearch(keyword, page):
  function get_up (line 740) | def get_up(uid, page):
  function get_bangumiinfo (line 760) | def get_bangumiinfo(url):
  function get_mp4info (line 857) | def get_mp4info(url):
  function get_comm (line 934) | def get_comm(url, sort):
  function get_bangumijson (line 1046) | def get_bangumijson(url):
  function get_vidquality (line 1058) | def get_vidquality(url):
  function get_bgmquality (line 1087) | def get_bgmquality(url):
  function get_biliplus_bgmquality (line 1138) | def get_biliplus_bgmquality(url):
  function get_api1 (line 1181) | def get_api1(url, quality):
  function get_api2 (line 1227) | def get_api2(url):
  function get_api3 (line 1279) | def get_api3(url, quality):
  function get_api4 (line 1378) | def get_api4(url, quality):
  function get_api5 (line 1451) | def get_api5(url, quality, api):
  function get_live (line 1515) | def get_live(page):
  function get_livemore (line 1531) | def get_livemore(url, page):
  function get_roominfo (line 1547) | def get_roominfo(id):
  function get_roommp4 (line 1592) | def get_roommp4(id):
  function get_categories (line 1607) | def get_categories():
  function get_videos (line 1639) | def get_videos(url):
  function get_sources (line 1738) | def get_sources(url):
  function get_collectlist (line 1839) | def get_collectlist(uid):
  function get_collect (line 1864) | def get_collect(id, page):
  function get_zhui (line 1890) | def get_zhui(uid, page, mode):
  function play (line 1924) | def play(name, url):
  function bangumiapi (line 2095) | def bangumiapi(name, url):
  function playvideo (line 2115) | def playvideo(cid, url):
  function api1 (line 2153) | def api1(name, url, quality):
  function api2 (line 2181) | def api2(name, url):
  function api3 (line 2205) | def api3(name, url, quality):
  function api4 (line 2237) | def api4(name, url, quality):
  function api5 (line 2257) | def api5(name, url, quality, api):
  function sources (line 2274) | def sources(url):
  function category (line 2288) | def category(url):
  function everyweek (line 2308) | def everyweek():
  function collectlist (line 2327) | def collectlist():
  function collect (line 2345) | def collect(id, page):
  function zhui (line 2368) | def zhui(page, mode):
  function index (line 2390) | def index():
  function my (line 2418) | def my():
  function sea (line 2446) | def sea():
  function search (line 2485) | def search(value, page):
  function bgsearch (line 2521) | def bgsearch(value, page):
  function movsearch (line 2557) | def movsearch(value, page):
  function vidsearch (line 2593) | def vidsearch(value, page):
  function livesearch (line 2629) | def livesearch(value, page):
  function upsearch (line 2664) | def upsearch(value, page):
  function vid (line 2699) | def vid(value):
  function roomid (line 2734) | def roomid(value):
  function live (line 2770) | def live():
  function livelist (line 2798) | def livelist(page):
  function livelistmore (line 2816) | def livelistmore(url, page):
  function room (line 2834) | def room(id):
  function up (line 2853) | def up(uid, page):
  function input (line 2903) | def input(key, value):
  function switch (line 2917) | def switch(key):
  function conn (line 2925) | def conn(url):
  function upinfo (line 2935) | def upinfo(uid):
  function show_label (line 2942) | def show_label(label):
  function get_key (line 2951) | def get_key(dict, value):
  function history (line 2956) | def history(name, url):
  function ok (line 3010) | def ok(value):
  function cleanhis (line 3016) | def cleanhis(url):

FILE: plugin.video.bilibili/danmuku.py
  function suffix (line 11) | def suffix(fileName, *suffixName):
  function deleteFile (line 19) | def deleteFile(path):
  function Danmuku (line 30) | def Danmuku(cid,path):

FILE: plugin.video.bilibili/xml2ass.py
  function SeekZero (line 34) | def SeekZero(function):
  function EOFAsNone (line 44) | def EOFAsNone(function):
  function ProbeCommentFormat (line 55) | def ProbeCommentFormat(f):
  function ReadCommentsNiconico (line 117) | def ReadCommentsNiconico(f, fontsize):
  function ReadCommentsAcfun (line 146) | def ReadCommentsAcfun(f, fontsize):
  function ReadCommentsBilibili (line 165) | def ReadCommentsBilibili(f, fontsize):
  function ReadCommentsTudou (line 185) | def ReadCommentsTudou(f, fontsize):
  function ReadCommentsMioMio (line 199) | def ReadCommentsMioMio(f, fontsize):
  function ReadCommentsSH5V (line 215) | def ReadCommentsSH5V(f, fontsize):
  function WriteCommentBilibiliPositioned (line 245) | def WriteCommentBilibiliPositioned(f, c, width, height, styleid):
  function WriteCommentAcfunPositioned (line 325) | def WriteCommentAcfunPositioned(f, c, width, height, styleid):
  function WriteCommentSH5VPositioned (line 436) | def WriteCommentSH5VPositioned(f, c, width, height, styleid):
  function GetZoomFactor (line 482) | def GetZoomFactor(SourceSize, TargetSize):
  function ConvertFlashRotation (line 512) | def ConvertFlashRotation(rotY, rotZ, X, Y, FOV=math.tan(2*math.pi/9.0)):
  function ProcessComments (line 564) | def ProcessComments(comments, f, width, height, bottomReserved, fontface...
  function TestFreeRows (line 599) | def TestFreeRows(rows, c, row, width, height, bottomReserved, lifetime):
  function FindAlternativeRow (line 629) | def FindAlternativeRow(rows, c, height, bottomReserved):
  function MarkCommentRow (line 639) | def MarkCommentRow(rows, c, row):
  function WriteASSHead (line 647) | def WriteASSHead(f, width, height, fontface, fontsize, alpha, styleid):
  function WriteComment (line 669) | def WriteComment(f, c, row, width, height, bottomReserved, fontsize, lif...
  function ASSEscape (line 689) | def ASSEscape(s):
  function CalculateLength (line 693) | def CalculateLength(s):
  function ConvertTimestamp (line 697) | def ConvertTimestamp(timestamp):
  function ConvertType2 (line 705) | def ConvertType2(row, height, bottomReserved):
  function ConvertToFile (line 709) | def ConvertToFile(filename_or_file, *args, **kwargs):
  function FilterBadChars (line 718) | def FilterBadChars(f):
  class safe_list (line 724) | class safe_list(list):
    method get (line 725) | def get(self, index, default=None):
  function export (line 732) | def export(func):
  function Danmaku2ASS (line 743) | def Danmaku2ASS(input_files, output_file, stage_width, stage_height, res...
  function ReadComments (line 758) | def ReadComments(input_files, font_size=25.0, progress_callback=None):
  function GetCommentProcessor (line 781) | def GetCommentProcessor(input_file):
  function main (line 785) | def main():

FILE: plugin.video.bimibimi[停止更新]/addon.py
  function unescape (line 17) | def unescape(string):
  function get_categories (line 30) | def get_categories():
  function get_videos (line 38) | def get_videos(url):
  function get_source (line 58) | def get_source(url):
  function get_mp4 (line 84) | def get_mp4(url):
  function play (line 112) | def play(url):
  function duop (line 125) | def duop(list):
  function source (line 140) | def source(url):
  function category (line 155) | def category(name,url):
  function index (line 173) | def index():
  function show_label (line 185) | def show_label(label):

FILE: plugin.video.changku/addon.py
  function get_mp4 (line 21) | def get_mp4(url):
  function unescape (line 42) | def unescape(string):
  function get_categories (line 50) | def get_categories():
  function get_shouye (line 76) | def get_shouye():
  function get_list (line 97) | def get_list(link):
  function get_videos (line 116) | def get_videos(url):
  function play (line 139) | def play(name,url):
  function category (line 149) | def category(name,url):
  function index (line 176) | def index():
  function show_label (line 188) | def show_label(label):

FILE: plugin.video.cine/addon.py
  function diff_float (line 26) | def diff_float(s1, s2):
  function urldecode (line 29) | def urldecode(fname):
  function chushihua (line 56) | def chushihua(key,default):
  function get_html (line 69) | def get_html(url,ua='pc',cf='',mode='html',encode='utf-8'):
  function post_html (line 118) | def post_html(url,data='',ua='pc',cf='',mode='html',encode='utf-8',jsons...
  function unix_to_data (line 178) | def unix_to_data(uptime,format='data'):
  function tiqu_num (line 200) | def tiqu_num(string):
  function get_categories_mode (line 207) | def get_categories_mode(mode):
  function get_videos_mode (line 210) | def get_videos_mode(url,mode,page):
  function get_source_mode (line 213) | def get_source_mode(url,mode):
  function get_mp4info_mode (line 216) | def get_mp4info_mode(url,mode):
  function get_mp4_mode (line 219) | def get_mp4_mode(url,mode):
  function get_search_mode (line 222) | def get_search_mode(keyword,page,mode):
  function get_categories (line 230) | def get_categories():
  function get_ku2000_categories (line 248) | def get_ku2000_categories():
  function get_ku2000_videos (line 268) | def get_ku2000_videos(url,page):
  function get_ku2000_source (line 285) | def get_ku2000_source(url):
  function get_ku2000_mp4 (line 309) | def get_ku2000_mp4(url):
  function get_ku2000_search (line 321) | def get_ku2000_search(keyword,page):
  function get_pianku_categories (line 340) | def get_pianku_categories():
  function get_pianku_videos (line 345) | def get_pianku_videos(url,page):
  function get_pianku_source (line 362) | def get_pianku_source(url):
  function get_pianku_mp4 (line 393) | def get_pianku_mp4(url):
  function get_pianku_search (line 403) | def get_pianku_search(keyword,page):
  function get_laodouban_categories (line 429) | def get_laodouban_categories():
  function get_laodouban_videos (line 435) | def get_laodouban_videos(url,page):
  function get_laodouban_source (line 453) | def get_laodouban_source(url):
  function get_laodouban_mp4 (line 496) | def get_laodouban_mp4(url):
  function get_laodouban_search (line 509) | def get_laodouban_search(keyword,page):
  function get_meijutt_categories (line 544) | def get_meijutt_categories():
  function get_meijutt_videos (line 552) | def get_meijutt_videos(url,page):
  function get_meijutt_source (line 571) | def get_meijutt_source(url):
  function get_meijutt_mp4 (line 597) | def get_meijutt_mp4(url):
  function get_meijutt_search (line 611) | def get_meijutt_search(keyword,page):
  function get_mahuazy_categories (line 634) | def get_mahuazy_categories():
  function get_mahuazy_videos (line 637) | def get_mahuazy_videos(url,page):
  function get_mahuazy_source (line 640) | def get_mahuazy_source(url):
  function get_mahuazy_mp4info (line 643) | def get_mahuazy_mp4info(url):
  function get_mahuazy_mp4 (line 646) | def get_mahuazy_mp4(url):
  function get_zdziyuan_categories (line 651) | def get_zdziyuan_categories():
  function get_zdziyuan_videos (line 654) | def get_zdziyuan_videos(url,page):
  function get_zdziyuan_source (line 657) | def get_zdziyuan_source(url):
  function get_zdziyuan_mp4info (line 660) | def get_zdziyuan_mp4info(url):
  function get_zdziyuan_mp4 (line 663) | def get_zdziyuan_mp4(url):
  function get_kukume_categories (line 667) | def get_kukume_categories():
  function get_letmetry_categories (line 670) | def get_letmetry_categories():
  function get_ddosi_categories (line 673) | def get_ddosi_categories():
  function get_yanzai_categories (line 676) | def get_yanzai_categories():
  function get_acrou_categories (line 678) | def get_acrou_categories():
  function play (line 687) | def play(name,url,mode):
  function hannum (line 706) | def hannum(x):
  function diff (line 713) | def diff(listA,listB):
  function duop (line 718) | def duop(name,list,mode):
  function source (line 734) | def source(name,url,img,mode):
  function category (line 749) | def category(name,url,mode,page):
  function home (line 784) | def home(mode):
  function onetogo (line 825) | def onetogo(name,url,mode,page):
  function search (line 871) | def search(value,page,mode):
  function get_key (line 913) | def get_key (dict, value):
  function history (line 917) | def history(name,url,mode):
  function ok (line 953) | def ok(value):
  function cleanhis (line 958) | def cleanhis(url):
  function index (line 964) | def index():
  function setting (line 1047) | def setting():
  function homesort (line 1064) | def homesort():
  function homeedit (line 1085) | def homeedit(value):
  function keyword (line 1098) | def keyword(key,name):
  function keywordxad (line 1123) | def keywordxad(key,value,mode):
  function switch (line 1175) | def switch(key):
  function show_label (line 1187) | def show_label(label):
  function get_xml (line 1201) | def get_xml(url,t=1,debug='no'):
  function get_xml_1hour (line 1215) | def get_xml_1hour(url):
  function get_xml_1day (line 1223) | def get_xml_1day(url):
  function get_maccms_xml (line 1230) | def get_maccms_xml(api,url=0,keyword=0,page=0,banid='',debug='no'):
  function get_json (line 1439) | def get_json(url,t=1,debug='no'):
  function get_json_1hour (line 1453) | def get_json_1hour(url):
  function get_json_1day (line 1461) | def get_json_1day(url):
  function get_maccms_json (line 1468) | def get_maccms_json(api,url=0,keyword=0,page=0,banid='',debug='no'):
  function get_sharelist (line 1696) | def get_sharelist(home):
  function get_goindex (line 1751) | def get_goindex(home):
  function get_yanzaigoindex (line 1771) | def get_yanzaigoindex(home):

FILE: plugin.video.clicli[停止更新]/addon.py
  function unescape (line 18) | def unescape(string):
  function jserror (line 30) | def jserror(html):
  function get_categories (line 38) | def get_categories():
  function get_videos (line 45) | def get_videos(url):
  function get_duop (line 67) | def get_duop(id):
  function get_mp4 (line 93) | def get_mp4(url):
  function play (line 105) | def play(name,url):
  function duop (line 116) | def duop(id):
  function category (line 131) | def category(name,url):
  function index (line 149) | def index():
  function show_label (line 161) | def show_label(label):

FILE: plugin.video.huanxi/addon.py
  function get_real_url (line 15) | def get_real_url(url):
  function unescape (line 19) | def unescape(string):
  function get_categories (line 32) | def get_categories():
  function get_shouying (line 37) | def get_shouying():
  function get_jilu (line 69) | def get_jilu():
  function get_mp4 (line 110) | def get_mp4(url):
  function get_videolist (line 129) | def get_videolist(url):
  function duop (line 211) | def duop(url):
  function play (line 222) | def play(name,url):
  function category (line 232) | def category(name,url):
  function index (line 256) | def index():
  function show_label (line 268) | def show_label(label):

FILE: plugin.video.kaiyan/addon.py
  function get_real_url (line 15) | def get_real_url(url):
  function unescape (line 19) | def unescape(string):
  function get_categories (line 32) | def get_categories():
  function get_tuijian_videos (line 38) | def get_tuijian_videos(url):
  function get_paihang_videos (line 84) | def get_paihang_videos(url):
  function get_zhuanti_videos (line 132) | def get_zhuanti_videos(category):
  function play (line 170) | def play(name,url):
  function category (line 179) | def category(name,url):
  function index (line 211) | def index():
  function show_label (line 223) | def show_label(label):

FILE: plugin.video.medicalvideo/addon.py
  function get_real_url (line 15) | def get_real_url(url):
  function unescape (line 19) | def unescape(string):
  function get_categories (line 32) | def get_categories():
  function get_videos (line 65) | def get_videos(cag):
  function get_duop (line 94) | def get_duop(url):
  function get_mp4_request (line 114) | def get_mp4_request(url):
  function get_mp4 (line 121) | def get_mp4(rect):
  function get_mp4info (line 143) | def get_mp4info(rect):
  function play (line 174) | def play(name,url):
  function category (line 194) | def category(name,url):
  function duop (line 211) | def duop(url):
  function index (line 229) | def index():
  function show_label (line 241) | def show_label(label):

FILE: plugin.video.pengpai[停止更新]/addon.py
  function get_real_url (line 15) | def get_real_url(url):
  function unescape (line 19) | def unescape(string):
  function get_categories (line 32) | def get_categories():
  function get_videos (line 48) | def get_videos(url):
  function play (line 82) | def play(name,url):
  function category (line 94) | def category(name,url):
  function index (line 114) | def index():
  function show_label (line 126) | def show_label(label):

FILE: plugin.video.reallive/addon.py
  function unescape (line 21) | def unescape(string):
  function chushihua (line 44) | def chushihua(key,default):
  function get_html (line 57) | def get_html(url,ua='pc',mode='html',encode='utf-8'):
  function post_html (line 81) | def post_html(url,data,json='off',ua='pc',mode='html',encode='utf-8'):
  function unix_to_data (line 115) | def unix_to_data(uptime,format='data'):
  function zh (line 138) | def zh(num):
  function tiqu_num (line 150) | def tiqu_num(string):
  function get_categories_mode (line 157) | def get_categories_mode(mode):
  function get_rooms_mode (line 160) | def get_rooms_mode(url,mode,page):
  function get_roomidinfo_mode (line 163) | def get_roomidinfo_mode(url,mode):
  function get_search_mode (line 166) | def get_search_mode(keyword,page,mode):
  function get_roomid_mode (line 169) | def get_roomid_mode(url,mode):
  function get_categories (line 176) | def get_categories():
  function get_huya_categories (line 196) | def get_huya_categories():
  function get_huya_rooms (line 202) | def get_huya_rooms(url,page):
  function get_huya_roomidinfo (line 217) | def get_huya_roomidinfo(url):
  function get_huya_roomid (line 248) | def get_huya_roomid(url):
  function get_douyu_categories (line 270) | def get_douyu_categories():
  function get_douyu_rooms (line 281) | def get_douyu_rooms(url,page):
  function get_douyu_roomidinfo (line 298) | def get_douyu_roomidinfo(url):
  function get_douyu_roomid (line 326) | def get_douyu_roomid(url):
  function get_homejs (line 361) | def get_homejs(rid):
  function get_sign (line 376) | def get_sign(rid, post_v, tt, ub9):
  function get_tt (line 390) | def get_tt():
  function get_pre_url (line 396) | def get_pre_url(rid, tt):
  function get_sign_url (line 421) | def get_sign_url(post_v, rid, tt, ub9):
  function get_chushou_categories (line 440) | def get_chushou_categories():
  function get_chushou_rooms (line 451) | def get_chushou_rooms(url,page):
  function get_chushou_roomidinfo (line 470) | def get_chushou_roomidinfo(url):
  function get_chushou_roomid (line 504) | def get_chushou_roomid(url):
  function get_chushou_search (line 539) | def get_chushou_search(keyword,page):
  function get_egame_categories (line 564) | def get_egame_categories():
  function get_egame_rooms (line 584) | def get_egame_rooms(url,page):
  function get_egame_roomidinfo (line 600) | def get_egame_roomidinfo(url):
  function get_egame_roomid (line 626) | def get_egame_roomid(url):
  function get_longzhu_categories (line 661) | def get_longzhu_categories():
  function get_longzhu_rooms (line 668) | def get_longzhu_rooms(url,page):
  function get_longzhu_roomidinfo (line 685) | def get_longzhu_roomidinfo(url):
  function get_longzhu_roomid (line 711) | def get_longzhu_roomid(url):
  function get_bilibili_categories (line 731) | def get_bilibili_categories():
  function get_bilibili_rooms (line 739) | def get_bilibili_rooms(url,page):
  function get_bilibili_roomidinfo (line 753) | def get_bilibili_roomidinfo(url):
  function get_bilibili_roomid (line 779) | def get_bilibili_roomid(url):
  function get_yy_categories (line 796) | def get_yy_categories():
  function get_yy_rooms (line 815) | def get_yy_rooms(url,page):
  function get_yy_roomidinfo (line 829) | def get_yy_roomidinfo(url):
  function get_yy_roomid (line 861) | def get_yy_roomid(url):
  function get_kuaishou_categories (line 888) | def get_kuaishou_categories():
  function get_kuaishou_rooms (line 904) | def get_kuaishou_rooms(url,page):
  function get_kuaishou_roomidinfo (line 924) | def get_kuaishou_roomidinfo(rid):
  function get_kuaishou_roomid (line 938) | def get_kuaishou_roomid(rid):
  function get_acfun_categories (line 969) | def get_acfun_categories():
  function get_acfun_roomid (line 971) | def get_acfun_roomid(url):
  function get_yangshipin_categories (line 994) | def get_yangshipin_categories():
  function get_yangshipin_rooms (line 997) | def get_yangshipin_rooms(url,page):
  function get_yangshipin_roomid (line 1022) | def get_yangshipin_roomid(url):
  function get_livechina_categories (line 1026) | def get_livechina_categories():
  function get_livechina_rooms (line 1029) | def get_livechina_rooms(url,page):
  function get_livechina_roomid (line 1110) | def get_livechina_roomid(url):
  function get_ipanda_categories (line 1114) | def get_ipanda_categories():
  function get_ipanda_rooms (line 1117) | def get_ipanda_rooms(url,page):
  function get_ipanda_roomid (line 1153) | def get_ipanda_roomid(url):
  function get_ithome_categories (line 1156) | def get_ithome_categories():
  function get_ithome_rooms (line 1159) | def get_ithome_rooms(url,page):
  function get_ithome_roomid (line 1198) | def get_ithome_roomid(url):
  function get_rooms (line 1217) | def get_rooms(url,mode,page):
  function rooms (line 1250) | def rooms(url,mode,page):
  function home (line 1255) | def home(mode):
  function search (line 1298) | def search(value,page,mode):
  function roomid (line 1341) | def roomid(value,mode):
  function get_key (line 1388) | def get_key (dict, value):
  function history (line 1392) | def history(name,url,mode):
  function ok (line 1437) | def ok(value):
  function cleanhis (line 1442) | def cleanhis(url):
  function index (line 1448) | def index():
  function setting (line 1531) | def setting():
  function homesort (line 1548) | def homesort():
  function homeedit (line 1569) | def homeedit(value):
  function keyword (line 1582) | def keyword(key,name):
  function keywordxad (line 1607) | def keywordxad(key,value,mode):
  function switch (line 1659) | def switch(key):
  function show_label (line 1671) | def show_label(label):

FILE: plugin.video.skypixel/addon.py
  function unescape (line 18) | def unescape(string):
  function get_categories (line 28) | def get_categories():
  function get_videos (line 37) | def get_videos(url):
  function play (line 57) | def play(name,url):
  function category (line 70) | def category(name,url):
  function index (line 88) | def index():
  function show_label (line 100) | def show_label(label):

FILE: plugin.video.taptap/addon.py
  function get_real_url (line 18) | def get_real_url(url):
  function unescape (line 22) | def unescape(string):
  function get_html_longtimecache (line 40) | def get_html_longtimecache(url,ua='pc',cookie='',mode='html',encode='utf...
  function get_html (line 45) | def get_html(url,ua='pc',cookie='',mode='html',encode='utf-8'):
  function post_html (line 90) | def post_html(url,data='',ua='pc',cookie='',mode='html',encode='utf-8',j...
  function unix_to_data (line 150) | def unix_to_data(uptime,format='data'):
  function data_to_unix (line 187) | def data_to_unix(dt,format='datatime'):
  function zh (line 208) | def zh(num):
  function get_categories (line 223) | def get_categories():
  function get_videos (line 246) | def get_videos(url,page):
  function play (line 549) | def play(name,url):
  function category (line 633) | def category(url,page):
  function index (line 663) | def index():
  function show_label (line 675) | def show_label(label):

FILE: plugin.video.vid/addon.py
  function unescape (line 20) | def unescape(string):
  function chushihua (line 37) | def chushihua(key,default):
  function check_filter (line 50) | def check_filter(text):
  function if_filter (line 58) | def if_filter(text):
  function get_videos_mode (line 65) | def get_videos_mode(page,mode):
  function get_mp4info_mode (line 69) | def get_mp4info_mode(url,mode):
  function get_mp4_mode (line 72) | def get_mp4_mode(url,mode):
  function get_html (line 77) | def get_html(url):
  function post_html (line 83) | def post_html(url,data):
  function unix_to_data (line 90) | def unix_to_data(uptime,format):
  function get_categories (line 97) | def get_categories():
  function get_huxiu_videos (line 108) | def get_huxiu_videos(page):
  function get_huxiu_mp4info (line 130) | def get_huxiu_mp4info(url):
  function get_huxiu_mp4 (line 155) | def get_huxiu_mp4(url):
  function get_gcore_videos (line 177) | def get_gcore_videos(page):
  function get_gcore_mp4info (line 196) | def get_gcore_mp4info(url):
  function get_gcore_mp4 (line 219) | def get_gcore_mp4(url):
  function get_qyer_videos (line 239) | def get_qyer_videos(page):
  function get_qyer_mp4info (line 261) | def get_qyer_mp4info(url):
  function get_qyer_mp4 (line 276) | def get_qyer_mp4(url):
  function get_zeal_videos (line 287) | def get_zeal_videos(page):
  function get_zeal_mp4info (line 313) | def get_zeal_mp4info(url):
  function get_zeal_mp4 (line 330) | def get_zeal_mp4(url):
  function get_pengpai_videos (line 349) | def get_pengpai_videos(page):
  function get_pengpai_mp4info (line 373) | def get_pengpai_mp4info(url):
  function get_pengpai_mp4 (line 394) | def get_pengpai_mp4(url):
  function get_bjnews_videos (line 401) | def get_bjnews_videos(page):
  function get_bjnews_mp4info (line 434) | def get_bjnews_mp4info(url):
  function get_bjnews_mp4 (line 449) | def get_bjnews_mp4(url):
  function get_jiemian_videos (line 456) | def get_jiemian_videos(page):
  function get_jiemian_mp4info (line 479) | def get_jiemian_mp4info(url):
  function get_jiemian_mp4 (line 491) | def get_jiemian_mp4(url):
  function get_36kr_videos (line 498) | def get_36kr_videos(page):
  function get_36kr_mp4info (line 540) | def get_36kr_mp4info(url):
  function get_36kr_mp4 (line 554) | def get_36kr_mp4(url):
  function get_huanqiu_videos (line 561) | def get_huanqiu_videos(page):
  function get_huanqiu_mp4info (line 581) | def get_huanqiu_mp4info(url):
  function get_huanqiu_mp4 (line 592) | def get_huanqiu_mp4(url):
  function play (line 599) | def play(name,url,mode):
  function category (line 611) | def category(page,mode):
  function index (line 642) | def index():
  function setting (line 696) | def setting():
  function homesort (line 713) | def homesort():
  function homeedit (line 734) | def homeedit(value):
  function keyword (line 747) | def keyword(key,name):
  function keywordxad (line 772) | def keywordxad(key,value,mode):
  function switch (line 824) | def switch(key):
  function show_label (line 835) | def show_label(label):

FILE: plugin.video.weibotv/addon.py
  function unescape (line 16) | def unescape(string):
  function get_categories (line 30) | def get_categories():
  function get_videos (line 44) | def get_videos(url):
  function get_sources (line 158) | def get_sources(videolink):
  function sources (line 183) | def sources(url):
  function category (line 196) | def category(url):
  function index (line 216) | def index():
  function show_label (line 228) | def show_label(label):

FILE: plugin.video.xigua[停止更新]/addon.py
  function get_real_url (line 19) | def get_real_url(url):
  function unescape (line 23) | def unescape(string):
  function cook (line 37) | def cook():
  function writewafid (line 69) | def writewafid(keyword):
  function testvideo (line 78) | def testvideo():
  function get_mp4 (line 95) | def get_mp4(url):
  function get_duop (line 146) | def get_duop(url,mode):
  function get_videos (line 181) | def get_videos(cag):
  function get_categories (line 261) | def get_categories():
  function duop (line 271) | def duop(url):
  function play (line 281) | def play(name,url):
  function category (line 292) | def category(name,url):
  function index (line 310) | def index():
  function ilist (line 324) | def ilist():
  function show_label (line 357) | def show_label(label):
  function link (line 370) | def link():
  function album (line 401) | def album():
  function wafid (line 428) | def wafid():
  function ykjtb (line 446) | def ykjtb(mode):
  function netcut (line 503) | def netcut(mode):

FILE: plugin.video.xinpianchang/addon.py
  function get_html_10min (line 20) | def get_html_10min(url, head=''):
  function get_html_1min (line 31) | def get_html_1min(url, head=''):
  function unescape (line 41) | def unescape(string):
  function get_categories (line 48) | def get_categories():
  function get_mp4 (line 69) | def get_mp4(url):
  function get_videos (line 99) | def get_videos(url, page):
  function play (line 141) | def play(name, url):
  function category (line 157) | def category(url, page):
  function index (line 174) | def index():
  function show_label (line 185) | def show_label(label):

FILE: service.subtitles.acfun/resources/lib/xml2ass.py
  function SeekZero (line 43) | def SeekZero(function):
  function EOFAsNone (line 53) | def EOFAsNone(function):
  function ProbeCommentFormat (line 64) | def ProbeCommentFormat(f):
  function ReadCommentsNiconico (line 132) | def ReadCommentsNiconico(f, fontsize):
  function ReadCommentsAcfun (line 161) | def ReadCommentsAcfun(f, fontsize):
  function ReadCommentsBilibili (line 182) | def ReadCommentsBilibili(f, fontsize):
  function ReadCommentsTudou (line 204) | def ReadCommentsTudou(f, fontsize):
  function ReadCommentsTudou2 (line 218) | def ReadCommentsTudou2(f, fontsize):
  function ReadCommentsMioMio (line 238) | def ReadCommentsMioMio(f, fontsize):
  function ReadCommentsSH5V (line 254) | def ReadCommentsSH5V(f, fontsize):
  function WriteCommentBilibiliPositioned (line 284) | def WriteCommentBilibiliPositioned(f, c, width, height, styleid):
  function WriteCommentAcfunPositioned (line 366) | def WriteCommentAcfunPositioned(f, c, width, height, styleid):
  function WriteCommentSH5VPositioned (line 480) | def WriteCommentSH5VPositioned(f, c, width, height, styleid):
  function GetZoomFactor (line 526) | def GetZoomFactor(SourceSize, TargetSize):
  function ConvertFlashRotation (line 555) | def ConvertFlashRotation(rotY, rotZ, X, Y, width, height):
  function ProcessComments (line 593) | def ProcessComments(comments, f, width, height, bottomReserved, fontface...
  function TestFreeRows (line 628) | def TestFreeRows(rows, c, row, width, height, bottomReserved, duration_m...
  function FindAlternativeRow (line 658) | def FindAlternativeRow(rows, c, height, bottomReserved):
  function MarkCommentRow (line 668) | def MarkCommentRow(rows, c, row):
  function WriteASSHead (line 676) | def WriteASSHead(f, width, height, fontface, fontsize, alpha, styleid):
  function WriteComment (line 701) | def WriteComment(f, c, row, width, height, bottomReserved, fontsize, dur...
  function ASSEscape (line 725) | def ASSEscape(s):
  function CalculateLength (line 738) | def CalculateLength(s):
  function ConvertTimestamp (line 742) | def ConvertTimestamp(timestamp):
  function ConvertColor (line 750) | def ConvertColor(RGB, width=1280, height=576):
  function ConvertType2 (line 769) | def ConvertType2(row, height, bottomReserved):
  function ConvertToFile (line 773) | def ConvertToFile(filename_or_file, *args, **kwargs):
  function FilterBadChars (line 782) | def FilterBadChars(f):
  class safe_list (line 788) | class safe_list(list):
    method get (line 790) | def get(self, index, default=None):
  function export (line 797) | def export(func):
  function Danmaku2ASS (line 807) | def Danmaku2ASS(input_files, output_file, stage_width, stage_height, res...
  function ReadComments (line 822) | def ReadComments(input_files, font_size=25.0, progress_callback=None):
  function GetCommentProcessor (line 845) | def GetCommentProcessor(input_file):
  function main (line 849) | def main():

FILE: service.subtitles.acfun/service.py
  function log (line 41) | def log(module, msg):
  function GetHttpData (line 45) | def GetHttpData(url, data=''):
  function Search (line 64) | def Search( item ):
  function Download (line 132) | def Download(url):
  function get_params (line 251) | def get_params():

FILE: service.subtitles.bilibili/resources/lib/xml2ass.py
  function SeekZero (line 43) | def SeekZero(function):
  function EOFAsNone (line 53) | def EOFAsNone(function):
  function ProbeCommentFormat (line 64) | def ProbeCommentFormat(f):
  function ReadCommentsNiconico (line 132) | def ReadCommentsNiconico(f, fontsize):
  function ReadCommentsAcfun (line 161) | def ReadCommentsAcfun(f, fontsize):
  function ReadCommentsBilibili (line 182) | def ReadCommentsBilibili(f, fontsize):
  function ReadCommentsTudou (line 204) | def ReadCommentsTudou(f, fontsize):
  function ReadCommentsTudou2 (line 218) | def ReadCommentsTudou2(f, fontsize):
  function ReadCommentsMioMio (line 238) | def ReadCommentsMioMio(f, fontsize):
  function ReadCommentsSH5V (line 254) | def ReadCommentsSH5V(f, fontsize):
  function WriteCommentBilibiliPositioned (line 284) | def WriteCommentBilibiliPositioned(f, c, width, height, styleid):
  function WriteCommentAcfunPositioned (line 366) | def WriteCommentAcfunPositioned(f, c, width, height, styleid):
  function WriteCommentSH5VPositioned (line 480) | def WriteCommentSH5VPositioned(f, c, width, height, styleid):
  function GetZoomFactor (line 526) | def GetZoomFactor(SourceSize, TargetSize):
  function ConvertFlashRotation (line 555) | def ConvertFlashRotation(rotY, rotZ, X, Y, width, height):
  function ProcessComments (line 593) | def ProcessComments(comments, f, width, height, bottomReserved, fontface...
  function TestFreeRows (line 628) | def TestFreeRows(rows, c, row, width, height, bottomReserved, duration_m...
  function FindAlternativeRow (line 658) | def FindAlternativeRow(rows, c, height, bottomReserved):
  function MarkCommentRow (line 668) | def MarkCommentRow(rows, c, row):
  function WriteASSHead (line 676) | def WriteASSHead(f, width, height, fontface, fontsize, alpha, styleid):
  function WriteComment (line 701) | def WriteComment(f, c, row, width, height, bottomReserved, fontsize, dur...
  function ASSEscape (line 725) | def ASSEscape(s):
  function CalculateLength (line 738) | def CalculateLength(s):
  function ConvertTimestamp (line 742) | def ConvertTimestamp(timestamp):
  function ConvertColor (line 750) | def ConvertColor(RGB, width=1280, height=576):
  function ConvertType2 (line 769) | def ConvertType2(row, height, bottomReserved):
  function ConvertToFile (line 773) | def ConvertToFile(filename_or_file, *args, **kwargs):
  function FilterBadChars (line 782) | def FilterBadChars(f):
  class safe_list (line 788) | class safe_list(list):
    method get (line 790) | def get(self, index, default=None):
  function export (line 797) | def export(func):
  function Danmaku2ASS (line 807) | def Danmaku2ASS(input_files, output_file, stage_width, stage_height, res...
  function ReadComments (line 822) | def ReadComments(input_files, font_size=25.0, progress_callback=None):
  function GetCommentProcessor (line 845) | def GetCommentProcessor(input_file):
  function main (line 849) | def main():

FILE: service.subtitles.bilibili/service.py
  function log (line 39) | def log(module, msg):
  function GetHttpData (line 43) | def GetHttpData(url, data=''):
  function Search (line 62) | def Search( item ):
  function Download (line 119) | def Download(url):
  function get_params (line 209) | def get_params():
Condensed preview — 176 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,804K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 58,
    "preview": "\ncustom: [\"afdian.net/@zhengfan2014\", \"paypal.me/nxsoft\"]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/------.md",
    "chars": 234,
    "preview": "---\nname: \"\\U0001F308功能要求\"\nabout: 为这个项目提出一个想法\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**您的功能请求是否与问题有关? 请描述**\n清楚简洁地说明问题所"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/-----.md",
    "chars": 354,
    "preview": "---\nname: \"❌错误报告\"\nabout: 创建报告以帮助我们改进\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**描述错误**\n清楚简明地描述错误是什么\n\n**重现**\n重现行为的步骤:\n1. "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/----.md",
    "chars": 222,
    "preview": "---\nname: 功能要求\nabout: 为这个项目提出一个想法\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**您的功能请求是否与问题有关? 请描述**\n清楚简洁地说明问题所在\n\n**描述您想要的解"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/auto.py",
    "chars": 1912,
    "preview": "#!/usr/bin/python\n# -*- coding: UTF-8 -*-\nimport os\nimport re\nimport xml.etree.cElementTree as et\nimport zipfile\nimport "
  },
  {
    "path": ".github/workflows/auto.yml",
    "chars": 1115,
    "preview": "name: kodi 插件自动化\non: push\n\njobs: \n  my-job: \n    runs-on: ubuntu-latest\n    name: 打包Kodi插件并自动更新插件库\n    steps: \n    - nam"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2020 zhengfan2014\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 10701,
    "preview": "# zhengfan2014的kodi插件仓库\n![xbmc-kodi-private-china-addons](https://socialify.git.ci/zhengfan2014/xbmc-kodi-private-china-"
  },
  {
    "path": "addons.xml",
    "chars": 12065,
    "preview": "<?xml version='1.0' encoding='UTF-8'?>\n<addons><addon id=\"metadata.douban.com.python\" name=\"豆瓣刮削器Python\" provider-name=\""
  },
  {
    "path": "addons.xml.md5",
    "chars": 32,
    "preview": "4e63ef3b358c798d9253b01d3d5f5c1c"
  },
  {
    "path": "metadata.douban.com.python/LICENSE.txt",
    "chars": 17988,
    "preview": "Valid-License-Identifier: GPL-2.0-or-later\nSPDX-URL:https://spdx.org/licenses/GPL-2.0-or-later.html\nUsage-Guide:\n  To us"
  },
  {
    "path": "metadata.douban.com.python/README.md",
    "chars": 488,
    "preview": "## The Movie Database Python scraper for Kodi\n\nThis is early work on a Python movie scraper for Kodi.\n\n### Manual search"
  },
  {
    "path": "metadata.douban.com.python/addon.xml",
    "chars": 947,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"metadata.douban.com.python\" name=\"豆瓣刮削器Python\" versio"
  },
  {
    "path": "metadata.douban.com.python/python/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/__init__.py",
    "chars": 334,
    "preview": "\ndef get_imdb_id(uniqueids):\n    imdb_id = uniqueids.get('imdb')\n    if not imdb_id or not imdb_id.startswith('tt'):\n   "
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/api_utils.py",
    "chars": 2669,
    "preview": "# coding: utf-8\n#\n# Copyright (C) 2020, Team Kodi\n#\n# This program is free software: you can redistribute it and/or modi"
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/fanarttv.py",
    "chars": 2896,
    "preview": "from . import api_utils\ntry:\n    from urllib import quote\nexcept ImportError: # py2 / py3\n    from urllib.parse import q"
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/imdbratings.py",
    "chars": 2451,
    "preview": "# -*- coding: UTF-8 -*-\n#\n# Copyright (C) 2020, Team Kodi\n#\n# This program is free software: you can redistribute it and"
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/tmdb.py",
    "chars": 10446,
    "preview": "from datetime import datetime, timedelta\nfrom . import tmdbapi\n\n\nclass TMDBMovieScraper(object):\n    def __init__(self, "
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/tmdbapi.py",
    "chars": 4476,
    "preview": "# -*- coding: UTF-8 -*-\n#\n# Copyright (C) 2020, Team Kodi\n#\n# This program is free software: you can redistribute it and"
  },
  {
    "path": "metadata.douban.com.python/python/lib/tmdbscraper/traktratings.py",
    "chars": 1993,
    "preview": "# -*- coding: UTF-8 -*-\n#\n# Copyright (C) 2020, Team Kodi\n#\n# This program is free software: you can redistribute it and"
  },
  {
    "path": "metadata.douban.com.python/python/scraper.py",
    "chars": 18130,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport json\nimport sys\nimport xbmc\nimport xbmcaddon\nimport xbmcgui\nimport x"
  },
  {
    "path": "metadata.douban.com.python/python/scraper_config.py",
    "chars": 4154,
    "preview": "def configure_scraped_details(details, settings):\n    details = _configure_rating_prefix(details, settings)\n    details "
  },
  {
    "path": "metadata.douban.com.python/python/scraper_datahelper.py",
    "chars": 1960,
    "preview": "import re\ntry:\n    from urlparse import parse_qsl\nexcept ImportError: # py2 / py3\n    from urllib.parse import parse_qsl"
  },
  {
    "path": "metadata.douban.com.python/resources/language/Chinese (Simple)/strings.po",
    "chars": 223,
    "preview": "msgid \"\"\nmsgstr \"\"\n\n#Chinese Simplified\n\nmsgctxt \"#33001\"\nmsgid \"proxy\"\nmsgstr \"代理设置\"\n\nmsgctxt \"#33002\"\nmsgid \"cloudflar"
  },
  {
    "path": "metadata.douban.com.python/resources/settings.xml",
    "chars": 328,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<settings>\n\t<category label=\"33001\" id=\"proxy\">\n\t\t<setting label"
  },
  {
    "path": "plugin.audio.jsososo/addon.py",
    "chars": 56150,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin, xbmcgui, xbmc, xbmcaddon, xbmcplug"
  },
  {
    "path": "plugin.audio.jsososo/addon.xml",
    "chars": 900,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.audio.jsososo\" name=\"Jsososo\" version=\"0.1.1\" "
  },
  {
    "path": "plugin.audio.jsososo/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.audio.jsososo/resources/language/Chinese (Simple)/strings.po",
    "chars": 1145,
    "preview": "msgid \"\"\nmsgstr \"\"\n\n#Chinese Simplified\n\nmsgctxt \"#32001\"\nmsgid \"api Setting\"\nmsgstr \"Api设置\"\n\nmsgctxt \"#32002\"\nmsgid \"ap"
  },
  {
    "path": "plugin.audio.jsososo/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.audio.jsososo/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.audio.jsososo/resources/settings.xml",
    "chars": 1238,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<settings>\n    <category label=\"32001\">\n      <setting label=\"32"
  },
  {
    "path": "plugin.video.acfun/addon.py",
    "chars": 27576,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.acfun/addon.xml",
    "chars": 761,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.acfun\" name=\"Acfun\" version=\"0.2.3\" prov"
  },
  {
    "path": "plugin.video.acfun/readme.md",
    "chars": 345,
    "preview": "# acfun for kodi 0.2.1\n## 简介\n- AcFun是一家弹幕视频网站,致力于为每一个人带来欢乐\n## 主要功能\n> - [x] 视频分类\n> - [x] 在线播放1080p视频\n> - [x] 使用官方api解析视频\n"
  },
  {
    "path": "plugin.video.acfun/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.acfun/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.acfun/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bangumi/addon.py",
    "chars": 87227,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin,xbmcaddon,xbmc\nimport requests\nfrom"
  },
  {
    "path": "plugin.video.bangumi/addon.xml",
    "chars": 955,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.bangumi\" name=\"Bangumi beta\" version=\"0."
  },
  {
    "path": "plugin.video.bangumi/readme.md",
    "chars": 1213,
    "preview": "# bangumi for kodi 0.2.0\n## :black_nib: 简介\n- bangumi插件是一个番剧网站聚合插件,它是vid插件的改进版,为适配番剧网站而生\n\n---\n## 主要功能\n适配网站 | 网址\n---- | --"
  },
  {
    "path": "plugin.video.bangumi/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bangumi/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.bangumi/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bangumi/resources/lib/zhcdict.json",
    "chars": 278476,
    "preview": "{\n\"SIMPONLY\": \"㐷㐹㐽㑇㑈㑔㑩㓆㓥㓰㔉㖊㖞㗷㘎㚯㛀㛟㛠㛣㛤㛿㟆㟜㟥㡎㤘㤽㥪㧏㧐㧑㧟㧰㨫㭎㭏㭣㭤㭴㱩㱮㲿㳔㳕㳠㳡㳢㳽㴋㶉㶶㶽㺍㻅㻏㻘䀥䁖䂵䃅䅉䅟䅪䇲䉤䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿䍀䍁䍠䎬䏝䑽䓓䓕䓖䓨䗖䘛䘞䙊䙌䙓䜣䜤䜥䜧䜩䝙䞌䞍䞎䞐䟢䢀䢁"
  },
  {
    "path": "plugin.video.bangumi/resources/lib/zhconv.py",
    "chars": 17011,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\nThis module implements a simple conversion and localization between si"
  },
  {
    "path": "plugin.video.bilibili/addon.py",
    "chars": 120869,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport base64\nimport hashlib\nimport HTMLParser\nimport json\nimport random\nim"
  },
  {
    "path": "plugin.video.bilibili/addon.xml",
    "chars": 967,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.bilibili\" name=\"Bilibili\" version=\"0.5.8"
  },
  {
    "path": "plugin.video.bilibili/danmuku.py",
    "chars": 1686,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\n\nimport requests\nimport xml2ass\nimport os\nimport io\nimport shutil\n\n#获取文件后缀名"
  },
  {
    "path": "plugin.video.bilibili/readme.md",
    "chars": 2415,
    "preview": "# bilibili for kodi 0.5.6\n## 简介\n- bilibili是国内知名的视频弹幕网站,这里有最及时的动漫新番,最棒的ACG氛围,最有创意的Up主。大家可以在这里找到许多欢乐\n## 主要功能\n> - [x] 视频分类\n"
  },
  {
    "path": "plugin.video.bilibili/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bilibili/resources/language/Chinese (Simple)/strings.po",
    "chars": 1444,
    "preview": "msgid \"\"\nmsgstr \"\"\n\n#Chinese Simplified\n\nmsgctxt \"#32001\"\nmsgid \"Login Setting\"\nmsgstr \"登录设置\"\n\nmsgctxt \"#32002\"\nmsgid \"m"
  },
  {
    "path": "plugin.video.bilibili/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.bilibili/resources/language/resource.language.en_us/strings.po",
    "chars": 2122,
    "preview": "# flsusr <flsusr@a-ca.pro>, 2020.\nmsgid \"\"\nmsgstr \"\"\n\"Last-Translator: flsusr <flsusr@a-ca.pro>\\n\"\n\"PO-Revision-Date: 20"
  },
  {
    "path": "plugin.video.bilibili/resources/language/resource.language.zh_cn/strings.po",
    "chars": 1444,
    "preview": "msgid \"\"\nmsgstr \"\"\n\n#Chinese Simplified\n\nmsgctxt \"#32001\"\nmsgid \"Login Setting\"\nmsgstr \"登录设置\"\n\nmsgctxt \"#32002\"\nmsgid \"m"
  },
  {
    "path": "plugin.video.bilibili/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bilibili/resources/settings.xml",
    "chars": 1608,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<settings>\n    <category label=\"32001\">\n      <setting label=\"32"
  },
  {
    "path": "plugin.video.bilibili/xml2ass.py",
    "chars": 37583,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\n\n\n# The original author of this program, Danmaku2ASS, is StarBrilliant.\n# T"
  },
  {
    "path": "plugin.video.bimibimi[停止更新]/addon.py",
    "chars": 5653,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.bimibimi[停止更新]/addon.xml",
    "chars": 964,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.bimibimi\" name=\"Bimibimi\" version=\"0.1.0"
  },
  {
    "path": "plugin.video.bimibimi[停止更新]/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.bimibimi[停止更新]/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.bimibimi[停止更新]/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.changku/addon.py",
    "chars": 6696,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.changku/addon.xml",
    "chars": 888,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.changku\" name=\"场库\" version=\"0.1.0\" provi"
  },
  {
    "path": "plugin.video.changku/readme.md",
    "chars": 273,
    "preview": "# 场库 for kodi 0.1.0\n## 简介\n- 高品质短片分享平台,汇集优秀视频短片及微电影创作人,实时不断分享全球优秀视频短片,微电影\n## 主要功能\n> - [x] 视频分类\n> - [x] 首页推荐,最新推荐,热门排行,星级精"
  },
  {
    "path": "plugin.video.changku/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.changku/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.changku/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.cine/addon.py",
    "chars": 76925,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.cine/addon.xml",
    "chars": 949,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.cine\" name=\"Cine beta\" version=\"0.1.0\" p"
  },
  {
    "path": "plugin.video.cine/readme.md",
    "chars": 1064,
    "preview": "# cine for kodi 0.2.0\n## :black_nib: 简介\n- cine插件是一个电影网站聚合插件,它是vid插件的改进版,为适配电影网站而生\n\n---\n## 主要功能\n适配网站 | 网址\n---- | ---- \n喜欢"
  },
  {
    "path": "plugin.video.cine/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.cine/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.cine/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.clicli[停止更新]/addon.py",
    "chars": 5068,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.clicli[停止更新]/addon.xml",
    "chars": 972,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.clili\" name=\"clicli\" version=\"0.1.0\" pro"
  },
  {
    "path": "plugin.video.clicli[停止更新]/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.clicli[停止更新]/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.clicli[停止更新]/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.huanxi/addon.py",
    "chars": 9047,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.huanxi/addon.xml",
    "chars": 926,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.huanxi\" name=\"欢喜首映\" version=\"0.1.0\" prov"
  },
  {
    "path": "plugin.video.huanxi/readme.md",
    "chars": 388,
    "preview": "# 欢喜首映 for kodi 0.1.0\n## 简介\n- 欢喜首映拥有王家卫、徐峥、陈可辛、宁浩、顾长卫、张一白、贾樟柯、张艺谋等巨匠影人为平台定制的大制作网剧、网络大电影,将视频播放与内容制作合二为一,首映厅首发好电影\n## 主要功能\n"
  },
  {
    "path": "plugin.video.huanxi/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.huanxi/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.huanxi/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.kaiyan/addon.py",
    "chars": 7202,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.kaiyan/addon.xml",
    "chars": 744,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.kaiyan\" name=\"开眼\" version=\"0.1.0\" provid"
  },
  {
    "path": "plugin.video.kaiyan/readme.md",
    "chars": 230,
    "preview": "# 开眼 for kodi 0.1.0\n## 简介\n- 精选视频推荐,每日大开眼界\n## 主要功能\n> - [x] 每日推荐\n> - [x] 日排行,周排行\n> - [ ] 专题\n> - [x] 在线播放视频(只有720p)\n> - [x]"
  },
  {
    "path": "plugin.video.kaiyan/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.kaiyan/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.kaiyan/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.medicalvideo/addon.py",
    "chars": 7492,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.medicalvideo/addon.xml",
    "chars": 997,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.medicalvideo\" name=\"医学微视\" version=\"0.1.0"
  },
  {
    "path": "plugin.video.medicalvideo/readme.md",
    "chars": 10,
    "preview": "dev版本,没做好哈"
  },
  {
    "path": "plugin.video.medicalvideo/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.medicalvideo/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.medicalvideo/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.pengpai[停止更新]/addon.py",
    "chars": 4858,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.pengpai[停止更新]/addon.xml",
    "chars": 863,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.pengpai\" name=\"澎湃\" version=\"0.1.0\" provi"
  },
  {
    "path": "plugin.video.pengpai[停止更新]/readme.md",
    "chars": 250,
    "preview": "# 澎湃视频 for kodi 0.1.0[停止更新]\n# 澎湃新闻kodi插件代码已合并到vid插件内,本插件不再维护\n## 简介\n- 不满足于琐碎的片段,做有态度的新闻视频\n## 主要功能\n> - [x] 视频分类\n> - [x] 在线"
  },
  {
    "path": "plugin.video.pengpai[停止更新]/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.pengpai[停止更新]/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.pengpai[停止更新]/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.reallive/addon.py",
    "chars": 79004,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.reallive/addon.xml",
    "chars": 911,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.reallive\" name=\"Reallive\" version=\"0.1.3"
  },
  {
    "path": "plugin.video.reallive/readme.md",
    "chars": 1242,
    "preview": "# Reallive for kodi 0.1.1\n## 简介\n- Reallive是一个直播聚合插件,Real取自对本插件帮助巨大的开源项目wbt5大佬的Real-url,以表示对该开源项目的感谢!更多直播网站和功能后续支持\n## 主要功"
  },
  {
    "path": "plugin.video.reallive/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.reallive/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.reallive/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.skypixel/addon.py",
    "chars": 3731,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.skypixel/addon.xml",
    "chars": 895,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.skypixel\" name=\"天空之城\" version=\"0.1.0\" pr"
  },
  {
    "path": "plugin.video.skypixel/readme.md",
    "chars": 253,
    "preview": "# 天空之城 for kodi 0.1.0\n## 简介\n- 世界各地的航拍摄影师、拍手叫绝的航拍作品与独具价值的航拍攻略。全世界的探索者们互相启发,乐在其中\n## 主要功能\n> - [x] 视频分类\n> - [x] 在线播放视频,支持任意选"
  },
  {
    "path": "plugin.video.skypixel/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.skypixel/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.skypixel/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.taptap/addon.py",
    "chars": 30632,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.taptap/addon.xml",
    "chars": 952,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.taptap\" name=\"Taptap\" version=\"0.2.2\" pr"
  },
  {
    "path": "plugin.video.taptap/readme.md",
    "chars": 362,
    "preview": "# taptap for kodi 0.1.0\n## 简介\n- TapTap是一个推荐高品质手游的手游分享社区,实时同步全球各大应用市场游戏排行榜,与全球玩家共同交流并发掘高品质手游。每一款推荐游戏,都是由专业的测评团队从全球海量的游戏中精"
  },
  {
    "path": "plugin.video.taptap/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.taptap/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.taptap/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.vid/addon.py",
    "chars": 29121,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.vid/addon.xml",
    "chars": 921,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.vid\" name=\"vid beta\" version=\"0.1.0\" pro"
  },
  {
    "path": "plugin.video.vid/readme.md",
    "chars": 18255,
    "preview": "# VID for kodi 0.1.0(说明还没有写好)\n## 🎯简介\n- vid插件是一个模块化,方便不是很懂kodi的python新手快速开发的插件,python新手无需知道kodi相关知识,只需知道一点python知识和遵循一定规则"
  },
  {
    "path": "plugin.video.vid/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.vid/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.vid/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.weibotv/addon.py",
    "chars": 8361,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.weibotv/addon.xml",
    "chars": 771,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.weibotv\" name=\"微博视频\" version=\"0.1.1\" pro"
  },
  {
    "path": "plugin.video.weibotv/readme.md",
    "chars": 275,
    "preview": "# 微博视频 for kodi 0.1.1\n## 简介\n- 随时随地发现新鲜事!微博带你欣赏世界上每一个精彩瞬间,了解每一个幕后故事\n## 主要功能\n> - [x] 视频分类\n> - [x] 在线播放视频\n> - [x] 使用官方api解析"
  },
  {
    "path": "plugin.video.weibotv/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.weibotv/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.weibotv/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.xigua[停止更新]/addon.py",
    "chars": 21938,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin\nimport requests\nfrom bs4 import Bea"
  },
  {
    "path": "plugin.video.xigua[停止更新]/addon.xml",
    "chars": 920,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.xigua\" name=\"西瓜视频\" version=\"0.2.0\" provi"
  },
  {
    "path": "plugin.video.xigua[停止更新]/readme.md",
    "chars": 344,
    "preview": "# 西瓜视频 for kodi 0.1.0\n## 简介\n- 西瓜视频是字节跳动旗下视频平台,通过个性化推荐为您提供新鲜、好看的视频内容,并帮助视频创作人们轻松地向全世界分享自己的视频作品,更有原创综艺节目等你来看\n## 主要功能\n> - ["
  },
  {
    "path": "plugin.video.xigua[停止更新]/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.xigua[停止更新]/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.xigua[停止更新]/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.xinpianchang/addon.py",
    "chars": 8784,
    "preview": "#!/usr/bin/env python\n# -*- coding:utf-8 -*-\nimport re\nfrom xbmcswift2 import Plugin,xbmcgui,xbmcplugin\nimport requests\n"
  },
  {
    "path": "plugin.video.xinpianchang/addon.xml",
    "chars": 923,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"plugin.video.xinpianchang\" name=\"新片场\" version=\"0.1.1\""
  },
  {
    "path": "plugin.video.xinpianchang/readme.md",
    "chars": 269,
    "preview": "# 新片场 for kodi 0.1.0\n## 简介\n- 新片场汇聚全球原创优质视频及创作人,提供4K、无广告、无水印视频观看,专业的视频艺术学习教程,正版视觉素材交易等,与数百万创作人一起用作品打动世界\n## 主要功能\n> - [x] 视"
  },
  {
    "path": "plugin.video.xinpianchang/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "plugin.video.xinpianchang/resources/language/English/strings.xml",
    "chars": 139,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<strings>\n  <!-- Plugin name -->\n  <string id=\"30000\">bilibili</"
  },
  {
    "path": "plugin.video.xinpianchang/resources/lib/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "service.subtitles.acfun/addon.xml",
    "chars": 1126,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"service.subtitles.acfun\"\n       name=\"Acfun 弹幕\"\n    "
  },
  {
    "path": "service.subtitles.acfun/readme.md",
    "chars": 390,
    "preview": "# Acfun 弹幕插件 for kodi 0.1.1\n## 简介\n- 获取并挂载acfun任意视频和番剧的弹幕,支持配合acfun插件显示弹幕,也可以用于本地nas上的番剧或者bangumi插件显示弹幕\n## 主要功能\n> - [x] 搜"
  },
  {
    "path": "service.subtitles.acfun/resources/lib/__init__.py",
    "chars": 47,
    "preview": "# Dummy file to make this directory a package.\n"
  },
  {
    "path": "service.subtitles.acfun/resources/lib/xml2ass.py",
    "chars": 40317,
    "preview": "#!/usr/bin/env python2\n# -*- coding: utf-8 -*-\n\n# The original author of this program, Danmaku2ASS, is StarBrilliant.\n# "
  },
  {
    "path": "service.subtitles.acfun/service.py",
    "chars": 13824,
    "preview": "# -*- coding: utf-8 -*-\n\nimport os\nimport sys\nimport xbmc\nimport urllib\nimport urllib2\nimport json\nimport xbmcvfs\nimport"
  },
  {
    "path": "service.subtitles.bilibili/addon.xml",
    "chars": 1130,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addon id=\"service.subtitles.bilibili\"\n       name=\"Bilibili 弹幕"
  },
  {
    "path": "service.subtitles.bilibili/readme.md",
    "chars": 382,
    "preview": "# Bilibili 弹幕插件 for kodi 0.1.1\n## 简介\n- 获取并挂载bilibili任意视频和番剧的弹幕,支持配合bilibili插件显示弹幕,也可以用于本地nas上的番剧或者bangumi插件显示弹幕\n## 主要功能\n"
  },
  {
    "path": "service.subtitles.bilibili/resources/lib/__init__.py",
    "chars": 47,
    "preview": "# Dummy file to make this directory a package.\n"
  },
  {
    "path": "service.subtitles.bilibili/resources/lib/xml2ass.py",
    "chars": 40317,
    "preview": "#!/usr/bin/env python2\n# -*- coding: utf-8 -*-\n\n# The original author of this program, Danmaku2ASS, is StarBrilliant.\n# "
  },
  {
    "path": "service.subtitles.bilibili/service.py",
    "chars": 12107,
    "preview": "# -*- coding: utf-8 -*-\n\nimport os\nimport sys\nimport xbmc\nimport urllib\nimport urllib2\nimport json\nimport xbmcvfs\nimport"
  },
  {
    "path": "step1/README.MD",
    "chars": 29,
    "preview": "# hi 这里是存放python抓取xx视频列表的原型代码"
  },
  {
    "path": "step1/acfun-rank-list.py",
    "chars": 732,
    "preview": "#acfun爬全站排行榜列表\nimport json\nimport requests\n\nurl = 'https://www.acfun.cn/rest/pc-direct/rank/channel?channelId=155&subCha"
  },
  {
    "path": "step1/acfun-video.py",
    "chars": 1056,
    "preview": "import requests\nimport json\n#多p:https://www.acfun.cn/v/ac3202810_4\n#单p:https://www.acfun.cn/v/ac12607834\nurl = 'https://"
  },
  {
    "path": "step1/bangumi.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "step1/bilibili-all-list.py",
    "chars": 3217,
    "preview": "#bangumi-list和video-list的整合\n#!/usr/bin/python\n# -*- coding: UTF-8 -*- \nfrom bs4 import BeautifulSoup\nimport re\nimport re"
  },
  {
    "path": "step1/bilibili-bangumi-list.py",
    "chars": 874,
    "preview": "#b站爬番剧列表\nimport json\nimport requests\nimport re\nfrom bs4 import BeautifulSoup\n\nurl = 'https://m.bilibili.com/bangumi/play"
  },
  {
    "path": "step1/bilibili-rank-list.py",
    "chars": 138663,
    "preview": "#b站全站排行列表\nfrom bs4 import BeautifulSoup\nhtml_doc = \"\"\"\n\n\n<!DOCTYPE html><html lang=\"zh-Hans\"><head><title>热门视频排行榜 - 哔哩哔哩"
  },
  {
    "path": "step1/bilibili-video-api.py",
    "chars": 1461,
    "preview": "import json\nimport requests\nimport re\nimport random\nfrom bs4 import BeautifulSoup\nhash = '45de7ffc02c0fdeb49263721999a5d"
  },
  {
    "path": "step1/bilibili-video-list.py",
    "chars": 1912,
    "preview": "import json\nimport requests\nimport re\nfrom bs4 import BeautifulSoup\n\nurl = 'https://www.bilibili.com/video/av91222524'\n#"
  },
  {
    "path": "step1/kaiyan.py",
    "chars": 3630,
    "preview": "#开眼每日精选\nimport requests\nimport json\nurl = 'http://baobab.kaiyanapp.com/api/v5/index/tab/allRec?page=0'\nheaders = {'user-"
  },
  {
    "path": "step1/livideo.py",
    "chars": 1043,
    "preview": "\nimport requests\nfrom bs4 import BeautifulSoup\n\n#首次加载网页\nurl = 'https://www.pearvideo.com/popular'\nheaders = {'user-agent"
  },
  {
    "path": "step1/pengpai.py",
    "chars": 1241,
    "preview": "#爬视频列表\nimport json \nimport requests\nfrom bs4 import BeautifulSoup\n\nurl = 'https://www.thepaper.cn/load_video_chosen.jsp?"
  },
  {
    "path": "step1/taptap.py",
    "chars": 4724,
    "preview": "\n#编辑推荐视频列表\nimport json \nimport requests\nfrom bs4 import BeautifulSoup\n\nurl = 'https://www.taptap.com/webapiv2/video/v1/r"
  },
  {
    "path": "step1/weibo.py",
    "chars": 5393,
    "preview": "#热门推荐(纪录片,评测,娱乐都没有)\nimport json \nimport requests\nimport re\nfrom bs4 import BeautifulSoup\nimport urllib\n\nurl = 'https://w"
  },
  {
    "path": "step1/weibomiaopai的js加密算法破解.py",
    "chars": 669,
    "preview": "import json \nimport requests\nimport base64\nfrom bs4 import BeautifulSoup\n\nurl = 'https://weibomiaopai.com/online-video-d"
  },
  {
    "path": "step1/医学卫视.py",
    "chars": 2169,
    "preview": "#视频列表\nimport json \nimport requests\nfrom bs4 import BeautifulSoup\n\nurl = 'https://www.mvyxws.com/'\nheaders = {'user-agent"
  },
  {
    "path": "step1/国土公开课.py",
    "chars": 2517,
    "preview": "#视频列表\nimport json \nimport requests\nfrom bs4 import BeautifulSoup\n\nurl = 'http://open.nlc.cn/onlineedu/course/explore/sea"
  },
  {
    "path": "step1/新片场和场库.py",
    "chars": 3518,
    "preview": "#视频列表\nimport json \nimport requests\nfrom bs4 import BeautifulSoup\n\nurl = 'https://www.xinpianchang.com/channel/index/id-8"
  }
]

About this extraction

This page contains the full source code of the zhengfan2014/xbmc-kodi-private-china-addons GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 176 files (1.3 MB), approximately 569.8k tokens, and a symbol index with 833 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!