Skip to content

Commit

Permalink
Trakt:适配 Plex
Browse files Browse the repository at this point in the history
  • Loading branch information
kjtsune committed Sep 4, 2023
1 parent 7e2d9bf commit 6c5186a
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 21 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ macOS 可能无法开机自启
* 会自动开启 WebUI,系统防火墙提示的时候可以拒绝(不影响使用)。
* 会自动开启 WebUI,建议仅允许从 localhost 访问: 查看 > 选项 > Web 界面:
打勾 仅允许从 localhost 访问
* MPC 播放 http 具有加载和拖动慢,视频总时长可能有误的缺点。
* MPC 播放 http 具有加载和拖动慢,视频总时长可能有误的缺点。
以及点击关闭播放器后,进程可能残留在后台。

> IINA
Expand All @@ -180,6 +181,25 @@ macOS 可能无法开机自启

## 其他:

> Trakt 相关
* 不推荐使用的理由:
1. 媒体服务器一般本身就有 Trakt 插件。
2. 只能往 Trakt 单向同步。
3. 只在正常播放器关闭后,同步播放器已播放的(网页点击已播放不触发)。
4. 配置和使用都麻烦。
* 使用说明:
1. 安装依赖:`python -m pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com/simple requests`
2. [Trakt app 管理页面](https://trakt.tv/oauth/applications)
创建 app,名字任意,Redirect uri 填写: `http://localhost/trakt` ,然后保存。
3. ini 配置文件`[trakt]` 填写 `enable_host` `user_name` `client_id` `client_secret` 这四项。
4. 点击 app 详情页面的 `Authorize` 按钮,二次同意后,复制网址并填到配置文件 `oauth_code` 里。
5. 启动脚本,播放一个视频,拖到最后,关闭播放器。看日志是否同步成功。
* 常见问题:
1. 若同步失败。电影看是否缺失IMDb,剧集看单集下方是否有 IMDb 或 TheTVDB。
2. 目录下`trakt_token.json`可以复制给新电脑用。然后删除原来的,并填写新的 `oauth_code` 来重新生成。
如果只是复制到新电脑,重复使用 token 的话,有效期只有三个月。

> Jellyfin 相关
* 首页播放结束后,10秒内重复播放**同文件**,本地播放器收到的播放时间会有误。
Expand Down
25 changes: 24 additions & 1 deletion embyToLocalPlayer_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ b = F:\TV

[playlist]

# 需要开启播放列表的域名所包含的字符,逗号隔开。禁用就留空或删除。
# 需要开启播放列表的域名的关键词,逗号隔开。禁用就留空或删除。
enable_host = localhost, 127.0.0.1, 192.168. , 192-168-, example.com:8096

# 切换下一集时的字幕优先顺序,逗号隔开,仅处理外挂字幕。
Expand Down Expand Up @@ -117,6 +117,29 @@ mix_log = yes
path_check = no


##################################################################
### v v # # # # # # # Trakt 设置 , 详见 FAQ # # # # # # # # v v ###

[trakt]

# 启用此功能的域名关键词,逗号隔开,不填则禁用此功能。例如:example.com:8096, plex.direct, 32400
enable_host =

# Trakt 的用户名,注意不是昵称。
user_name =

# 创建 app 时,重定向链接填:http://localhost/trakt
# 创建好的 trakt app 详情页 -> Client ID
client_id =

# 创建好的 trakt app 详情页 -> Client Secret
client_secret =

# 创建好的 trakt app 详情页 -> 点击 Authorize 按钮 -> 二次确认后的浏览器网址。
# 例如: http://localhost/trakt?code=60897439134095409edsoi3290
oauth_code =


##################################################################
### v v # # # # # # # # 文件缓存设置 # # # # # # # # # # # # v v ###

Expand Down
18 changes: 9 additions & 9 deletions user_script/embyToLocalPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// @name:zh-CN embyToLocalPlayer
// @name:en embyToLocalPlayer
// @namespace https://github.com/kjtsune/embyToLocalPlayer
// @version 1.1.8.2
// @version 1.1.9
// @description 需要 Python。Emby 调用外部本地播放器,并回传播放记录。适配 Jellyfin Plex。
// @description:zh-CN 需要 Python。Emby 调用外部本地播放器,并回传播放记录。适配 Jellyfin Plex。
// @description:en Require Python. Play in an external player. Update watch history to emby server. Support Jellyfin Plex.
Expand All @@ -20,19 +20,19 @@
// ==/UserScript==
'use strict';
/*
2023-09-04:
1. Trakt 播放记录单向同步。(详见 FAQ)
2. 剧集多版本:下一集匹配失败则禁用播放列表。
* 版本间累积更新:
* 自动选择视频版本(限emby,配置文件有新增条目 [dev])
* 油猴:非管理员可显示文件名。
2023-08-09:
1. 代理配置热更新。
* 版本间累积更新:
* 内封字幕无中文,且未选中字幕时(或无字幕时),尝试加载外挂字幕。(配置文件有新增条目 [dev] )
* 播放列表:下一集保持相同版本。(限emby,配置文件有新增条目)
* mpc 修复多版本播放回传失败。
2023-06-17:
1. 去除:AutoHotKey 依赖(感谢@verygoodlee)
2. 增加:根据路径选择播放器。
3. 修复:pot 播放列表可能异常。
* 版本间累积更新:
* 外挂字幕适配 Jellyfin 字幕烧录。
*/

let config = {
Expand Down Expand Up @@ -168,7 +168,7 @@ async function addOpenFolderElement() {
if (!pathDiv || pathDiv.className == 'mediaInfoItems' || pathDiv.id == 'addFileNameElement') return;
let full_path = pathDiv.textContent;
if (!full_path.match(/[/:]/)) return;
if (full_path.match(/\d{1,3}\.\d{1,2} (MB|GB)/)) return;
if (full_path.match(/\d{1,3}\.?\d{0,2} (MB|GB)/)) return;

let openButtonHtml = `<a id="openFolderButton" is="emby-linkbutton" class="raised item-tag-button
nobackdropfilter emby-button" ><i class="md-icon button-icon button-icon-left">link</i>Open Folder</a>`
Expand Down
7 changes: 4 additions & 3 deletions utils/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ def update_trakt_for_eps(eps):
useful_items.append(ep)
if useful_items:
from utils.trakt_sync import local_import_sync_ep_or_movie_to_trakt
local_import_sync_ep_or_movie_to_trakt(emby_items=useful_items)
names = [i['basename'] for i in useful_items]
logger.info(f'sync trakt {names}')
res = local_import_sync_ep_or_movie_to_trakt(emby_items=useful_items)
if res:
names = [i['basename'] for i in useful_items]
logger.info(f'sync trakt {names}')


def list_episodes_plex(data: dict):
Expand Down
11 changes: 10 additions & 1 deletion utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import subprocess
import threading
import time
import urllib.error
import urllib.parse
import urllib.request
import urllib.error
from concurrent.futures import ThreadPoolExecutor, as_completed
from http.server import HTTPServer
from typing import Union
Expand Down Expand Up @@ -582,6 +582,14 @@ def parse_received_data_plex(received_data):
total_sec = int(meta['duration']) // (10 ** 3)
position = start_sec / total_sec

provider_ids = [tuple(i['id'].split('://')) for i in meta['Guid']]
provider_ids = {k.title(): v for (k, v) in provider_ids}

trakt_emby_ver_dict = dict(
Type=meta['type'],
ProviderIds=provider_ids
)

playlist_diff_dict = dict(
basename=basename,
media_basename=media_basename,
Expand All @@ -603,6 +611,7 @@ def parse_received_data_plex(received_data):
rating_key=rating_key,
position=position,
)
res.update(trakt_emby_ver_dict)
res.update(playlist_diff_dict)
res.update(other_info_dict)
res_list.append(res)
Expand Down
14 changes: 8 additions & 6 deletions utils/trakt_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,29 @@ def sync_ep_or_movie_to_trakt(trakt, emby=None, emby_ids=None, emby_items=None):
if tvdb_id := provider_ids.get('Tvdb') and not trakt_ids:
trakt_ids = trakt.id_lookup('tvdb', tvdb_id)
if not trakt_ids:
logger.info('not trakt_ids')
logger.info('not trakt_ids, skip sync trakt')
continue
trakt_ids = trakt_ids[0]
watched = trakt.get_watch_history(trakt_ids)
if watched:
logger.info('trakt history exists, skip requests trakt')
logger.info('trakt history exists, skip sync trakt')
continue

trakt_ids_list.append(trakt_ids)
res = trakt.add_ep_or_movie_to_history(trakt_ids_list)
return res
if trakt_ids_list:
res = trakt.add_ep_or_movie_to_history(trakt_ids_list)
return res


def local_import_sync_ep_or_movie_to_trakt(emby_items=None, test=False):
from utils.trakt_api import TraktApi
user_id = configs.raw.get('trakt', 'user_id', fallback='')
user_id = configs.raw.get('trakt', 'user_name', fallback='')
client_id = configs.raw.get('trakt', 'client_id', fallback='')
client_secret = configs.raw.get('trakt', 'client_secret', fallback='')
oauth_code = configs.raw.get('trakt', 'oauth_code', fallback='').split('code=')
oauth_code = oauth_code[1] if len(oauth_code) == 2 else oauth_code[0]
if not all([user_id, client_id, client_secret]):
raise ValueError('require user_id, client_id, client_secret')
raise ValueError('require user_name, client_id, client_secret')
trakt = TraktApi(
user_id=user_id,
client_id=client_id,
Expand All @@ -52,4 +53,5 @@ def local_import_sync_ep_or_movie_to_trakt(emby_items=None, test=False):
return trakt
else:
res = sync_ep_or_movie_to_trakt(trakt=trakt, emby_items=emby_items)
res and logger.info('trakt:', res)
return res

0 comments on commit 6c5186a

Please sign in to comment.