Skip to content

Commit 129ef6b

Browse files
committed
minor bug fixes
1 parent 0f00576 commit 129ef6b

10 files changed

Lines changed: 245 additions & 43 deletions

File tree

LibVideo/AboutWindow.xaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Window x:Class="LibVideo.AboutWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
5+
Title="{DynamicResource AboutWindowTitle}" SizeToContent="WidthAndHeight" MinWidth="400" MaxWidth="600"
6+
WindowStartupLocation="CenterOwner"
7+
ResizeMode="NoResize"
8+
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
9+
Background="{DynamicResource MaterialDesignPaper}">
10+
<Grid Margin="24">
11+
<Grid.RowDefinitions>
12+
<RowDefinition Height="Auto"/>
13+
<RowDefinition Height="Auto"/>
14+
<RowDefinition Height="*"/>
15+
<RowDefinition Height="Auto"/>
16+
</Grid.RowDefinitions>
17+
18+
<TextBlock Text="LibVideo" FontSize="26" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,10" Foreground="{DynamicResource PrimaryHueMidBrush}"/>
19+
20+
<TextBlock Grid.Row="1" Text="{DynamicResource AboutDescription}" TextWrapping="Wrap" FontSize="14" TextAlignment="Center" Margin="0,0,0,20"/>
21+
22+
<StackPanel Grid.Row="2" VerticalAlignment="Center">
23+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,15">
24+
<materialDesign:PackIcon Kind="Web" VerticalAlignment="Center" Margin="0,0,8,0" Width="20" Height="20"/>
25+
<TextBlock FontSize="14"><Hyperlink NavigateUri="https://bookzhou.com" RequestNavigate="Hyperlink_RequestNavigate">https://bookzhou.com</Hyperlink></TextBlock>
26+
</StackPanel>
27+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
28+
<materialDesign:PackIcon Kind="Github" VerticalAlignment="Center" Margin="0,0,8,0" Width="20" Height="20"/>
29+
<TextBlock FontSize="14"><Hyperlink NavigateUri="https://github.com/transbot/LibVideo2" RequestNavigate="Hyperlink_RequestNavigate">https://github.com/transbot/LibVideo2</Hyperlink></TextBlock>
30+
</StackPanel>
31+
</StackPanel>
32+
33+
<Button Grid.Row="3" Content="{DynamicResource OKButton}" Style="{StaticResource MaterialDesignRaisedButton}" Width="100" HorizontalAlignment="Center" Margin="0,20,0,0" Click="Close_Click"/>
34+
</Grid>
35+
</Window>

LibVideo/AboutWindow.xaml.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Diagnostics;
2+
using System.Windows;
3+
using System.Windows.Navigation;
4+
5+
namespace LibVideo
6+
{
7+
public partial class AboutWindow : Window
8+
{
9+
public AboutWindow()
10+
{
11+
InitializeComponent();
12+
}
13+
14+
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
15+
{
16+
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });
17+
e.Handled = true;
18+
}
19+
20+
private void Close_Click(object sender, RoutedEventArgs e)
21+
{
22+
this.Close();
23+
}
24+
}
25+
}

LibVideo/App.xaml.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ protected override void OnStartup(StartupEventArgs e)
1616
string lang = File.ReadAllText("language.txt").Trim();
1717
ChangeLanguage(lang);
1818
}
19+
else
20+
{
21+
// First-time launch: check system locale
22+
if (!System.Threading.Thread.CurrentThread.CurrentUICulture.Name.StartsWith("zh", StringComparison.OrdinalIgnoreCase))
23+
{
24+
ChangeLanguage("en");
25+
File.WriteAllText("language.txt", "en");
26+
}
27+
else
28+
{
29+
File.WriteAllText("language.txt", "zh");
30+
}
31+
}
1932

2033
AppDomain.CurrentDomain.UnhandledException += (s, args) =>
2134
LogException(args.ExceptionObject as Exception);

LibVideo/LibVideo2.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@
113113
<Generator>MSBuild:Compile</Generator>
114114
<SubType>Designer</SubType>
115115
</Page>
116+
<Page Include="AboutWindow.xaml">
117+
<Generator>MSBuild:Compile</Generator>
118+
<SubType>Designer</SubType>
119+
</Page>
116120
<Page Include="SettingsWindow.xaml">
117121
<Generator>MSBuild:Compile</Generator>
118122
<SubType>Designer</SubType>
@@ -137,6 +141,10 @@
137141
<DependentUpon>SettingsWindow.xaml</DependentUpon>
138142
<SubType>Code</SubType>
139143
</Compile>
144+
<Compile Include="AboutWindow.xaml.cs">
145+
<DependentUpon>AboutWindow.xaml</DependentUpon>
146+
<SubType>Code</SubType>
147+
</Compile>
140148
<Compile Include="Models\VideoItem.cs" />
141149
<Compile Include="Models\MetadataService.cs" />
142150
<Compile Include="ViewModels\MainViewModel.cs" />

LibVideo/MainWindow.xaml

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
</StackPanel>
5454

5555
<StackPanel Orientation="Horizontal" Grid.Column="1" VerticalAlignment="Center">
56+
<Button x:Name="btnAbout" Style="{StaticResource MaterialDesignFloatingActionMiniButton}" Click="btnAbout_Click" Height="40" Width="40" ToolTip="{DynamicResource AboutToolTip}" Margin="0,0,10,0" Background="{DynamicResource PrimaryHueMidBrush}" BorderBrush="Transparent">
57+
<materialDesign:PackIcon Kind="InformationOutline" Height="24" Width="24" Foreground="White" />
58+
</Button>
5659
<Button Style="{StaticResource MaterialDesignFloatingActionMiniButton}" Command="{Binding RefreshCacheCommand}" Height="40" Width="40" ToolTip="{DynamicResource RefreshCacheToolTip}" Margin="0,0,10,0" Background="{DynamicResource PrimaryHueDarkBrush}" BorderBrush="Transparent">
5760
<materialDesign:PackIcon Kind="DatabaseRefresh" Height="24" Width="24" Foreground="White" />
5861
</Button>
@@ -100,9 +103,27 @@
100103
</DataTemplate>
101104
</DataGridTemplateColumn.CellTemplate>
102105
</DataGridTemplateColumn>
103-
<DataGridTextColumn Header="{DynamicResource HeaderId}" Binding="{Binding Id}" />
104-
<DataGridTextColumn Header="{DynamicResource HeaderPath}" Binding="{Binding FolderName}" Width="*" />
105-
<DataGridTextColumn Header="{DynamicResource HeaderFileName}" Binding="{Binding FileName}" Width="*" />
106+
<DataGridTextColumn Binding="{Binding Id}">
107+
<DataGridTextColumn.HeaderTemplate>
108+
<DataTemplate>
109+
<TextBlock Text="{DynamicResource HeaderId}" />
110+
</DataTemplate>
111+
</DataGridTextColumn.HeaderTemplate>
112+
</DataGridTextColumn>
113+
<DataGridTextColumn Binding="{Binding FolderName}" Width="*">
114+
<DataGridTextColumn.HeaderTemplate>
115+
<DataTemplate>
116+
<TextBlock Text="{DynamicResource HeaderPath}" />
117+
</DataTemplate>
118+
</DataGridTextColumn.HeaderTemplate>
119+
</DataGridTextColumn>
120+
<DataGridTextColumn Binding="{Binding FileName}" Width="*">
121+
<DataGridTextColumn.HeaderTemplate>
122+
<DataTemplate>
123+
<TextBlock Text="{DynamicResource HeaderFileName}" />
124+
</DataTemplate>
125+
</DataGridTextColumn.HeaderTemplate>
126+
</DataGridTextColumn>
106127
</DataGrid.Columns>
107128

108129
<DataGrid.ContextMenu>

LibVideo/MainWindow.xaml.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,12 @@ private void btnSettings_Click(object sender, RoutedEventArgs e)
5656
settingsWin.DataContext = this.DataContext;
5757
settingsWin.ShowDialog();
5858
}
59+
60+
private void btnAbout_Click(object sender, RoutedEventArgs e)
61+
{
62+
var aboutWin = new AboutWindow();
63+
aboutWin.Owner = this;
64+
aboutWin.ShowDialog();
65+
}
5966
}
6067
}

LibVideo/Models/MetadataService.cs

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,24 @@ public static class MetadataService
2222
private static readonly string TMDB_API_KEY = "b5355467863d25d8a7c03c204446034c";
2323
private static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
2424

25+
private static bool IsEnglish()
26+
{
27+
if (File.Exists("language.txt"))
28+
{
29+
string lang = File.ReadAllText("language.txt").Trim();
30+
if (lang == "en") return true;
31+
}
32+
return false;
33+
}
34+
2535
public static async Task<VideoMetadata> GetMetadataAsync(string videoFilePath)
2636
{
2737
if (string.IsNullOrEmpty(videoFilePath) || (!File.Exists(videoFilePath) && !Directory.Exists(videoFilePath)))
2838
return null;
2939

3040
string directory = File.Exists(videoFilePath) ? Path.GetDirectoryName(videoFilePath) : videoFilePath;
3141
string baseName = Path.GetFileNameWithoutExtension(videoFilePath);
42+
bool isEn = IsEnglish();
3243

3344
bool isAudio = false;
3445

@@ -50,7 +61,7 @@ public static async Task<VideoMetadata> GetMetadataAsync(string videoFilePath)
5061
if (audioExts.Contains(ext)) hasAudio = true;
5162
if (videoExts.Contains(ext)) hasVideo = true;
5263

53-
// 性能优化:只要发现任何一个视频文件,就说明这不是纯音频专辑,立即阻断扫描
64+
// 发现任何一个视频文件立即阻断扫描
5465
if (hasVideo) break;
5566
}
5667
if (hasAudio && !hasVideo) isAudio = true;
@@ -65,23 +76,26 @@ public static async Task<VideoMetadata> GetMetadataAsync(string videoFilePath)
6576

6677
if (isAudio)
6778
{
68-
var audioMeta = await Task.Run(() => GetLocalMetadata(directory, baseName));
79+
var audioMeta = await Task.Run(() => GetLocalMetadata(directory, baseName, isEn));
6980
if (audioMeta != null)
7081
{
71-
audioMeta.Genre = "音频";
72-
audioMeta.Plot = "您选择的是本地音乐/音频文件(或专有音频文件夹),目前暂无剧情简介。";
82+
audioMeta.Genre = isEn ? "Audio" : "音频";
83+
audioMeta.Plot = isEn ? "You have selected a local audio/music file. No plot available." : "您选择的是本地音乐/音频文件(或专有音频文件夹),目前暂无剧情简介。";
7384
}
7485
return audioMeta;
7586
}
7687

7788
var (searchName, searchYear) = CleanFileName(baseName);
7889

79-
var meta = await FetchFromTmdbAsync(searchName, searchYear, "zh-CN");
90+
string tmdbLang = isEn ? "en-US" : "zh-CN";
91+
var meta = await FetchFromTmdbAsync(searchName, searchYear, tmdbLang, isEn);
8092

81-
// 如果没搜到,或者搜到了但是由于没中文翻译导致简介为空,自动追搜一遍英文数据
82-
if (meta == null || meta.Plot == "该剧集/电影暂无对应的简介。")
93+
string noPlotMessage = isEn ? "No plot overview available." : "该剧集/电影暂无对应的简介。";
94+
95+
// 如果没搜到,或者搜到了但是中文没翻译导致简介为空(且不在英文模式下),自动追搜一遍英文数据
96+
if (!isEn && (meta == null || meta.Plot == noPlotMessage))
8397
{
84-
var enMeta = await FetchFromTmdbAsync(searchName, searchYear, "en-US");
98+
var enMeta = await FetchFromTmdbAsync(searchName, searchYear, "en-US", isEn);
8599
if (enMeta != null)
86100
{
87101
if (meta == null)
@@ -90,20 +104,20 @@ public static async Task<VideoMetadata> GetMetadataAsync(string videoFilePath)
90104
}
91105
else
92106
{
93-
if (enMeta.Plot != "该剧集/电影暂无对应的简介。")
107+
if (enMeta.Plot != noPlotMessage && enMeta.Plot != "No plot overview available.")
94108
meta.Plot = enMeta.Plot; // 借用英文简介
95109
}
96110
}
97111
}
98112

99113
if (meta == null)
100114
{
101-
meta = await Task.Run(() => GetLocalMetadata(directory, baseName));
115+
meta = await Task.Run(() => GetLocalMetadata(directory, baseName, isEn));
102116
}
103117

104-
if (meta != null && (string.IsNullOrEmpty(meta.Genre) || meta.Genre == "电影"))
118+
if (meta != null && (string.IsNullOrEmpty(meta.Genre) || meta.Genre == "电影" || meta.Genre == "Movie"))
105119
{
106-
meta.Genre = "视频";
120+
meta.Genre = isEn ? "Video" : "视频";
107121
}
108122

109123
return meta;
@@ -126,8 +140,6 @@ private static (string title, string year) CleanFileName(string fileName)
126140

127141
string[] tags = { "1080p", "720p", "2160p", "4k", "bluray", "webrip", "web-dl", "web dl", "hdrip", "x264", "x265", "hevc", "avc", "aac", "dts", "h264", "h265", "10bit", "hdr", "ddp", "atmos", "truehd", "remux", "itunes", "minibd", "cmct", "chdbits", "yify", "rarbg", "tvrip", "hdtv" };
128142

129-
130-
131143
foreach (var tag in tags)
132144
{
133145
cleaned = Regex.Replace(cleaned, $@"\b{tag}\b", " ", RegexOptions.IgnoreCase);
@@ -148,7 +160,6 @@ private static (string title, string year) CleanFileName(string fileName)
148160
}
149161
else
150162
{
151-
// 如果片名本身就是年份(如电影《1917》或《2012》),则不提取 Year 导致片名为空
152163
year = "";
153164
}
154165
}
@@ -162,18 +173,18 @@ private static (string title, string year) CleanFileName(string fileName)
162173
}
163174
}
164175

165-
private static async Task<VideoMetadata> FetchFromTmdbAsync(string query, string year, string language = "zh-CN")
176+
private static async Task<VideoMetadata> FetchFromTmdbAsync(string query, string year, string language, bool isEn)
166177
{
167178
if (string.IsNullOrWhiteSpace(query)) return null;
168179

169-
var movieMeta = await SearchTmdbCategoryAsync("movie", query, year, language);
180+
var movieMeta = await SearchTmdbCategoryAsync("movie", query, year, language, isEn);
170181
if (movieMeta != null) return movieMeta;
171182

172-
var tvMeta = await SearchTmdbCategoryAsync("tv", query, year, language);
183+
var tvMeta = await SearchTmdbCategoryAsync("tv", query, year, language, isEn);
173184
return tvMeta;
174185
}
175186

176-
private static async Task<VideoMetadata> SearchTmdbCategoryAsync(string category, string query, string year, string language)
187+
private static async Task<VideoMetadata> SearchTmdbCategoryAsync(string category, string query, string year, string language, bool isEn)
177188
{
178189
try
179190
{
@@ -197,7 +208,7 @@ private static async Task<VideoMetadata> SearchTmdbCategoryAsync(string category
197208
meta.Title = ExtractJsonString(firstObjJson, "title") ?? ExtractJsonString(firstObjJson, "name") ?? query;
198209

199210
string overview = ExtractJsonString(firstObjJson, "overview");
200-
meta.Plot = !string.IsNullOrWhiteSpace(overview) ? overview : "该剧集/电影暂无对应的简介。";
211+
meta.Plot = !string.IsNullOrWhiteSpace(overview) ? overview : (isEn ? "No plot overview available." : "该剧集/电影暂无对应的简介。");
201212

202213
string posterPath = ExtractJsonString(firstObjJson, "poster_path");
203214
if (!string.IsNullOrEmpty(posterPath))
@@ -208,7 +219,7 @@ private static async Task<VideoMetadata> SearchTmdbCategoryAsync(string category
208219
var genreIds = ExtractJsonArrayInts(firstObjJson, "genre_ids");
209220
if (genreIds.Count > 0)
210221
{
211-
var genres = genreIds.Select(id => GetTmdbGenre(id)).Where(g => g != null);
222+
var genres = genreIds.Select(id => GetTmdbGenre(id, isEn)).Where(g => g != null);
212223
meta.Genre = string.Join(", ", genres);
213224
}
214225

@@ -247,20 +258,29 @@ private static List<int> ExtractJsonArrayInts(string json, string key)
247258
return list;
248259
}
249260

250-
private static string GetTmdbGenre(int id)
261+
private static string GetTmdbGenre(int id, bool isEn)
251262
{
252-
var dict = new Dictionary<int, string>
263+
var dictZh = new Dictionary<int, string>
253264
{
254265
{ 28, "动作" }, { 12, "冒险" }, { 16, "动画" }, { 35, "喜剧" },
255266
{ 80, "犯罪" }, { 99, "纪录" }, { 18, "剧情" }, { 10751, "家庭" },
256267
{ 14, "奇幻" }, { 36, "历史" }, { 27, "恐怖" }, { 10402, "音乐" },
257268
{ 9648, "悬疑" }, { 10749, "爱情" }, { 878, "科幻" }, { 10770, "电视电影" },
258269
{ 53, "惊悚" }, { 10752, "战争" }, { 37, "西部" }
259270
};
271+
var dictEn = new Dictionary<int, string>
272+
{
273+
{ 28, "Action" }, { 12, "Adventure" }, { 16, "Animation" }, { 35, "Comedy" },
274+
{ 80, "Crime" }, { 99, "Documentary" }, { 18, "Drama" }, { 10751, "Family" },
275+
{ 14, "Fantasy" }, { 36, "History" }, { 27, "Horror" }, { 10402, "Music" },
276+
{ 9648, "Mystery" }, { 10749, "Romance" }, { 878, "Science Fiction" }, { 10770, "TV Movie" },
277+
{ 53, "Thriller" }, { 10752, "War" }, { 37, "Western" }
278+
};
279+
var dict = isEn ? dictEn : dictZh;
260280
return dict.ContainsKey(id) ? dict[id] : null;
261281
}
262282

263-
private static VideoMetadata GetLocalMetadata(string directory, string baseName)
283+
private static VideoMetadata GetLocalMetadata(string directory, string baseName, bool isEn)
264284
{
265285
var meta = new VideoMetadata();
266286
string[] possiblePosters = {
@@ -282,22 +302,22 @@ private static VideoMetadata GetLocalMetadata(string directory, string baseName)
282302
{
283303
var xdoc = XDocument.Load(nfoPath);
284304
meta.Title = xdoc.Descendants("title").FirstOrDefault()?.Value ?? baseName;
285-
meta.Plot = xdoc.Descendants("plot").FirstOrDefault()?.Value ?? "无简介。";
305+
meta.Plot = xdoc.Descendants("plot").FirstOrDefault()?.Value ?? (isEn ? "No plot." : "无简介。");
286306
var genres = xdoc.Descendants("genre").Select(x => x.Value).ToList();
287-
meta.Genre = genres.Any() ? string.Join(", ", genres) : "视频";
307+
meta.Genre = genres.Any() ? string.Join(", ", genres) : (isEn ? "Video" : "视频");
288308
}
289309
catch
290310
{
291311
meta.Title = baseName;
292-
meta.Plot = "读取 NFO 出错。";
293-
meta.Genre = "视频";
312+
meta.Plot = isEn ? "Error reading NFO." : "读取 NFO 出错。";
313+
meta.Genre = isEn ? "Video" : "视频";
294314
}
295315
}
296316
else
297317
{
298318
meta.Title = baseName;
299-
meta.Plot = "由于该视频未能自动匹配到线上数据库资料,暂无对应简介。您可以尝试修改文件名来提升匹配精度。";
300-
meta.Genre = "视频";
319+
meta.Plot = isEn ? "Due to unmatched online database record, no plot is currently available. You may try modifying the filename for better matching precision." : "由于该视频未能自动匹配到线上数据库资料,暂无对应简介。您可以尝试修改文件名来提升匹配精度。";
320+
meta.Genre = isEn ? "Video" : "视频";
301321
}
302322

303323
return meta;

0 commit comments

Comments
 (0)