tv2html:使用离线可浏览 HTML 对您的电视节目进行分类





5.00/5 (1投票)
生成一个可 Web 浏览的界面来访问您的存档电视节目内容
引言
我有一些几年前在 DVD 和蓝光上购买的节目,我已经将它们归档了,因为我讨厌光盘切换,而且我喜欢有备份。
问题在于浏览这些节目,这让我只能使用普通的 Windows 文件资源管理器或连接到智能电视的某种 DLNA 服务,当这些服务可用时还可以,但并非总是如此,例如旅行时。
我所做的是创建一个命令行实用程序,为您选择的电视节目创建一个可 Web 浏览的界面。它使用 themoviedb.org 的 REST API 来检索有关您节目的信息。然后,您可以浏览到您节目的根目录的 index.html 文件,它将提供一个可导航的界面,显示您所有的视频,并附带系列、季和集信息。
免责声明:有些读者可能会看到这个并想到“哇,我可以用我的盗版媒体来做这个!” - 对于这些读者,我无法阻止您如何使用它,但我也不赞成。而且,实际上,支付您想要的东西通常比运行 VPN 更便宜。
必备组件
- 您需要一台能够生成 Visual Studio .NET C# 控制台应用程序项目的机器
- 您需要一个来自 themoviedb.org 的授权令牌。创建一个免费账户,登录,然后转到“账户菜单”->“设置|API”来创建或检索您的授权令牌。不要将其与 API 密钥混淆。
更新:添加了配置文件支持。修复了错误。
背景
这个项目的大部分内容都是模拟的“ASP.NET 页面”,它们绑定到从 REST API 返回的 JSON。我的 csppg 项目用于将 .aspx 文件转换为可以从应用程序执行的 C# 代码。csppg 可执行文件在预编译事件中引用。
为了方便将数据绑定到 JSON,我们使用了 这段代码 的一个变种。
有一个核心的 Tmdb
对象,它处理应用程序的一些核心功能,例如进行 REST 查询或下载文件。
为了处理命令行解析和其他细节,该项目使用了我的 Program.Base 项目。
使用应用程序
下面,AUTH_TOKEN
应该是您从 themoviedb 网站获得的那个大而丑的哈希值。
搜索所有名称中包含“burn”的节目并列出它们
tv2html "burn" AUTH_TOKEN
搜索“Burn Notice” - 将生成到“TV”子目录,因为它将是唯一的匹配项
tv2html "burn notice" AUTH_TOKEN /output TV
生成节目 ID 2919(Burn Notice)并将结果写入当前目录。
tv2html #2919 AUTH_TOKEN
请注意,您可以通过在可执行文件的当前工作目录中提供一个 tv2html.config 文件来省略命令行中的身份验证令牌。该配置文件类似于 .NET 框架项目中的 App.config,但为了跨平台兼容性,不包含可执行文件的扩展名。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="authToken" value="AUTH_TOKEN"/>
</appSettings>
</configuration>
将 AUTH_TOKEN
替换为您的身份验证令牌。解决方案文件夹中提供了一个模板。
几件事
- 创建的目录结构遵循 [Series]\[Season]\[S0#E0# Episode Name] 的形式。
- index.html 文件是您的主要入口点。在系列文件夹和每个季文件夹中都有一个。
- 已创建或已下载的文件夹和图像不会被再次创建或下载。如果您想确保获得来自 The Movie DB 的最新信息,请删除它们。
- 在生成过程中,代码会查找文件夹中是否存在视频文件。如果找到受支持格式的视频文件,则该剧集页面将嵌入该视频。例如,它会搜索
Burn Notice\Season 1\S01E01 Pilot.(mp4|webm|mpeg|ogg)
。否则,它将列为不可用。如果您稍后添加更多视频,您将需要重新运行 tv2html 来重新生成您的页面。
编码应用程序
大部分工作由“aspx”文件完成。这些不是真正的 ASP.NET 页面。首先,它们不支持相同的指令,而且它们只支持 C#。此外,没有 Web 服务器的参与。相反,根解决方案文件夹中的 csppg 工具用于将这些类似 aspx 的文件转换为可以从应用程序调用的 C# 代码。我们使用此方法以及 .aspx 扩展名是为了获得 T4 引擎不提供的 IntelliSense,而且此工具不像 T4 那样需要大量投入。
主 Program.cs 的 Run()
方法仅处理最后的参数逻辑、初始获取以及运行模板。
- series.index.aspx 负责顶级的 index.html。
- season.index.aspx 负责每个季的 index.html。
- episode.aspx 负责每个剧集 html 文件。
如果您查看这些文件的内容,您会发现大量使用了 dynamic
关键字。这允许 C# 晚期绑定到我们的 JSON 元素,就好像它们是 C# 中原生的静态类型对象一样。
否则,索引文件就是灵活的网格布局,其中包含季或剧集数据。每个页面都有一个飞出导航侧边栏。剧集页面包含一个视频,如果找不到视频,则显示静态图像。
特别值得关注的是 Tmdb.cs 文件,它处理了一些关键的应用程序功能,包括将 JSON 元素公开为晚期可绑定对象、与 REST 服务器交互以及下载文件。我在介绍中链接的文章中已经介绍了 JSON 的晚期绑定,但我已将该文件中的其他功能发布在这里。
public static string GetSafeFilename(string file)
{
var result = "";
var inv = Path.GetInvalidFileNameChars();
var sb = new StringBuilder();
sb.Clear();
for (int j = 0; j < file.Length; j++)
{
if (Array.IndexOf(inv, file[j]) > -1)
{
sb.Append('_');
}
else
{
sb.Append(file[j]);
}
}
result = Path.Combine(result, sb.ToString());
return result;
}
public static JsonDocument GetJson(string url)
{
JsonDocument result;
using (var msg = new HttpRequestMessage(HttpMethod.Get, url))
{
msg.Headers.Clear();
msg.Headers.Add("accept", "application/json");
msg.Headers.Add("Authorization", "bearer " + AuthToken);
using (var resp = _client.Send(msg))
{
result = JsonDocument.Parse(resp.Content.ReadAsStream());
}
}
return result;
}
public static void Download(string url, string path, bool overwrite = false)
{
if (overwrite || !File.Exists(path))
{
using (var msg = new HttpRequestMessage(HttpMethod.Get, url))
{
using (var resp = _client.Send(msg))
{
var dir = Path.GetDirectoryName(path);
if(!Directory.Exists(dir))
{
Directory.CreateDirectory(dir!);
}
using (var outstm = File.OpenWrite(path))
{
resp.Content.ReadAsStream().CopyTo(outstm);
}
}
}
}
}
public static object GetObject(string url)
{
return new TmdbElement(GetJson(url).RootElement);
}
那里没有什么特别复杂的。GetSafeFilename()
函数只是将无效的文件名字符转换为下划线。其余的甚至更容易理解。
现在主要的混乱是我们处理所有逻辑的 ASPX 文件,并调用上面的函数。它们的格式不适合在此处放置源代码,但您可以看看它们。如果您熟悉 ASP.NET,应该不难理解。
历史
- 2024 年 4 月 10 日 - 初次提交
- 2024 年 4 月 10 日 - 添加了配置文件支持,修复了错误