Skip to content

Commit 5a0664a

Browse files
First public release.
1 parent ac7d180 commit 5a0664a

22 files changed

+690
-362
lines changed

.github/workflows/release.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
run: |
4343
git fetch origin master
4444
git checkout master
45-
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD -- CalibreImport/ReleaseFiles/CalibreImport.config CalibreImport/ReleaseFiles/*.dll CalibreImport/ReleaseFiles/Setup.ps1 CalibreImport/ReleaseFiles/CalibreImportSetup.exe)
45+
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD -- CalibreImport/ReleaseFiles/*.dll CalibreImport/ReleaseFiles/Setup.ps1 CalibreImport/ReleaseFiles/CalibreImportSetup.exe)
4646
echo "Changed files: $CHANGED_FILES"
4747
if [ -n "$CHANGED_FILES" ]; then
4848
echo "FILES_CHANGED=true" >> $GITHUB_ENV
@@ -122,12 +122,13 @@ jobs:
122122
exit 1
123123
fi
124124
125-
if [ ! -f "$BUILD_PATH/CalibreImport.config" ] || [ ! -f "$BUILD_PATH/Setup.ps1" ]; then
126-
echo "Warning: Some config files are missing. Continuing anyway."
127-
fi
125+
# no need to include the default config file, the app will create it dynamically.
126+
# if [ ! -f "$BUILD_PATH/CalibreImport.config" ] || [ ! -f "$BUILD_PATH/Setup.ps1" ]; then
127+
# echo "Warning: Some config files are missing. Continuing anyway."
128+
# fi
128129
129130
# Copy files with error handling
130-
cp $BUILD_PATH/*.dll $BUILD_PATH/CalibreImport.config $BUILD_PATH/Setup.ps1 release/ || {
131+
cp $BUILD_PATH/*.dll $BUILD_PATH/Setup.ps1 release/ || {
131132
echo "Warning: Some files could not be copied. Continuing with available files."
132133
}
133134

CalibreImport.rar

59.6 KB
Binary file not shown.

CalibreImport/AppSettings.cs

Lines changed: 0 additions & 11 deletions
This file was deleted.

CalibreImport/CalibreImport.cs

Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace CalibreImport
2323
[ClassInterface(ClassInterfaceType.None)]//, ComVisible(true)]
2424
[Guid("8E5CD5CA-64E0-479A-B62F-B1FC00FF0227")]
2525
[DisplayName("CalibreImport")]
26-
[COMServerAssociation(AssociationType.AllFiles)] //needed for Directory Opus, apparently.
26+
//[COMServerAssociation(AssociationType.AllFiles)] //needed for Directory Opus, apparently.
2727
[COMServerAssociation(AssociationType.ClassOfExtension, ".epub", ".pdf", ".mobi", ".azw", ".azw3", ".fb2", ".djvu", ".lrf", ".rtf", ".txt", ".doc", ".docx", ".odt", ".htm", ".html", ".cbz", ".cbr", ".pdb", ".snb", ".tcr", ".zip", ".rar")]
2828

2929
// Welcome to CalibreImport, the main class of this Shell Extension.
@@ -32,7 +32,8 @@ namespace CalibreImport
3232
// The class is decorated with various attributes to specify its COM visibility and associations with file types.
3333
public class CalibreImport : SharpContextMenu
3434
{
35-
private List<string> _supportedExtensions = new List<string>();
35+
// HashSet for supported extensions to improve lookup performance
36+
private HashSet<string> _supportedExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
3637

3738
// variables from the Settings file and their defaults
3839
private string MenuText = ResourceStrings.MenuTextRes;
@@ -43,7 +44,7 @@ public class CalibreImport : SharpContextMenu
4344
private string hiddenLibraries = CustomSettings.Config.AppSettings.Settings["hiddenLibraries"].Value ?? "";
4445
private bool skipSuccessMessage = bool.Parse(CustomSettings.Config.AppSettings.Settings["skipSuccessMessage"].Value ?? "False");
4546
private bool autoCalibreOpen = bool.Parse(CustomSettings.Config.AppSettings.Settings["autoCalibreOpen"].Value ?? "False");
46-
47+
private string savedCulture = CustomSettings.Config.AppSettings.Settings["language"].Value;
4748

4849
// List of Calibre-related processes to check
4950
private static readonly string[] CalibreProcesses = new[]
@@ -57,25 +58,28 @@ public class CalibreImport : SharpContextMenu
5758
"calibre-smtp"
5859
};
5960

61+
// Time checks for retrieveing file types in CanShowMenu
62+
private DateTime _lastExtensionsUpdate = DateTime.MinValue;
63+
private readonly TimeSpan _extensionCacheDuration = TimeSpan.FromMinutes(5);
64+
6065
// other variables
6166
private string dllDirectory;
6267
private string calibredbPath;
6368
private string calibrePath;
6469

65-
// Constructor: sets culture from settings,
66-
// and loads paths and supported file extensions
70+
// Constructor: calls on the CultureManager class to set culture,
71+
// and loads paths and supported file extensions.
6772
public CalibreImport()
6873
{
69-
// Load the saved language setting
70-
var savedCulture = CustomSettings.Config.AppSettings.Settings["language"].Value;
71-
if (!string.IsNullOrEmpty(savedCulture))
72-
{
73-
CultureInfo culture = new CultureInfo(savedCulture);
74-
Thread.CurrentThread.CurrentUICulture = culture;
75-
Thread.CurrentThread.CurrentCulture = culture;
76-
}
74+
// Ensure the default application culture is set FIRST before any other initialization
75+
CultureManager.SetApplicationCulture();
76+
77+
// Set default thread culture to ensure new threads use the correct culture
78+
CultureInfo culture = Thread.CurrentThread.CurrentUICulture;
79+
CultureInfo.DefaultThreadCurrentCulture = culture;
80+
CultureInfo.DefaultThreadCurrentUICulture = culture;
7781

78-
// Initialize other components or settings if needed
82+
// Initialize other components or settings
7983
InitializePaths();
8084
LoadSupportedExtensions();
8185
}
@@ -95,19 +99,23 @@ protected override bool CanShowMenu()
9599
{
96100
try
97101
{
98-
InitializePaths();
99-
LoadSupportedExtensions();
100-
102+
// Only reload extensions if needed
103+
if (_supportedExtensions == null || _supportedExtensions.Count == 0 ||
104+
DateTime.Now - _lastExtensionsUpdate > _extensionCacheDuration)
105+
{
106+
InitializePaths();
107+
LoadSupportedExtensions();
108+
_lastExtensionsUpdate = DateTime.Now;
109+
}
101110
// Log the selected item paths and supported extensions
102111
Logger.LogThis($"SelectedItemPaths: {string.Join(", ", SelectedItemPaths)}", true);
103-
Logger.LogThis($"SupportedExtensions: {string.Join(", ", _supportedExtensions)}", true);
112+
//Logger.LogThis($"SupportedExtensions: {string.Join(", ", _supportedExtensions)}", true);
104113

105114
// Ensure all selected items have supported extensions
106115
bool allSupported = SelectedItemPaths.Any(p => _supportedExtensions.Contains(Path.GetExtension(p).ToLower()));
107116
Logger.LogThis($"AllSupported: {allSupported}", true);
108117

109118
return allSupported;
110-
//return true;
111119
}
112120
catch (Exception ex)
113121
{
@@ -120,6 +128,9 @@ protected override bool CanShowMenu()
120128
// Handles both submenu and single menu item display modes based on user settings.
121129
protected override ContextMenuStrip CreateMenu()
122130
{
131+
// Make sure culture is set correctly before creating any UI text
132+
CultureManager.SetApplicationCulture();
133+
123134
var menu = new ContextMenuStrip();
124135
Logger.LogThis("Creating context menu.", true);
125136

@@ -217,6 +228,9 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
217228
{
218229
try
219230
{
231+
// Ensure culture is set correctly before displaying any messages
232+
CultureManager.SetApplicationCulture();
233+
220234
Logger.LogThis("ExecuteImport method called.", true);
221235

222236
InitializePaths();
@@ -233,6 +247,7 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
233247

234248
Logger.LogThis($"Found {filePaths.Count} supported files.", true);
235249

250+
// make sure calibredb.exe exists, otherwise bye-bye
236251
if (!File.Exists(calibredbPath))
237252
{
238253
Logger.LogThis($"Could not find calibredb.exe at {calibredbPath}. Please update the script with the correct path.");
@@ -243,13 +258,14 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
243258

244259
Logger.LogThis("calibredb.exe found.", true);
245260

261+
// What to do if Calibre is running
246262
if (IsCalibreRunning())
247263
{
248264
Logger.LogThis("Calibre is running.", true);
249265

250266
if (autoKillCalibre)
251267
{
252-
Logger.LogThis("Auto-killing Calibre.", true);
268+
Logger.LogThis("Auto-killing Calibre without asking.", true);
253269
KillCalibre();
254270
}
255271
else
@@ -299,11 +315,9 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
299315
return allSuccessful;
300316
};
301317

302-
using (var importForm = new ImportForm(libraries, importFunction))
303-
{
304-
importForm.Show();
305-
// The form will handle success messages and opening Calibre
306-
}
318+
var importForm = new ImportForm(libraries, importFunction);
319+
importForm.ShowDialog();
320+
307321
}
308322
else
309323
{
@@ -386,7 +400,11 @@ private bool ImportSingleFile(string libraryPath, string filePath)
386400
process.WaitForExit();
387401

388402
Logger.LogThis($"Process output: {output}", true);
389-
Logger.LogThis($"Process error: {error}", true);
403+
// Only log error output if it's not empty
404+
if (!string.IsNullOrWhiteSpace(error))
405+
{
406+
Logger.LogThis($"Process error: {error}", true);
407+
}
390408

391409
if (process.ExitCode == 0)
392410
{
@@ -537,45 +555,18 @@ int CalculateProgress(int current) =>
537555
}
538556
}
539557

540-
// Load ebook extensions supported by Calibre from Registry
558+
// Call on the SupportedFileTypes class
559+
// In order to rertrieve the list of supported file extensions
541560
private void LoadSupportedExtensions()
542561
{
543-
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\calibre\calibre64bit\Capabilities\FileAssociations"))
544-
{
545-
if (key != null)
546-
{
547-
_supportedExtensions = key.GetValueNames().ToList();
548-
return;
549-
}
550-
}
562+
_supportedExtensions.Clear();
551563

552-
_supportedExtensions = new List<string>
553-
{
554-
".epub", ".pdf", ".mobi", ".azw", ".azw3", ".fb2", ".djvu",
555-
".lrf", ".rtf", ".txt", ".doc", ".docx", ".odt", ".htm", ".html",
556-
".cbz", ".cbr", ".pdb", ".snb", ".tcr", ".zip", ".rar"
557-
};
558-
}
564+
// Use the centralized file extensions manager with HashSet for performance
565+
_supportedExtensions = SupportedFileTypes.GetExtensionsHashSet();
559566

560-
// Get the list of supported eBook file extensions
561-
private static List<string> GetFileExtensions()
562-
{
563-
var extensions = new List<string>();
564-
using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\calibre\calibre64bit\Capabilities\FileAssociations"))
565-
{
566-
if (key != null)
567-
{
568-
extensions = key.GetValueNames().ToList();
569-
return extensions;
570-
}
571-
}
572-
573-
return new List<string>
574-
{
575-
".epub", ".pdf", ".mobi", ".azw", ".azw3", ".fb2", ".djvu",
576-
".lrf", ".rtf", ".txt", ".doc", ".docx", ".odt", ".htm", ".html",
577-
".cbz", ".cbr", ".pdb", ".snb", ".tcr", ".zip", ".rar"
578-
};
567+
Logger.LogThis($"Loaded {_supportedExtensions.Count} supported extensions from " +
568+
(_supportedExtensions.Count > SupportedFileTypes.DefaultExtensions.Length ?
569+
"registry." : "default list."), true);
579570
}
580571

581572
// Check if any Calibre-related process is running
@@ -584,8 +575,7 @@ private bool IsCalibreRunning()
584575
return CalibreProcesses.Any(processName => Process.GetProcessesByName(processName).Any());
585576
}
586577

587-
// Attempts to terminate all Calibre-related processes
588-
// Prompts for user confirmation unless auto-kill is enabled
578+
// Attempts to terminate all Calibre-related processes, if any.
589579
private void KillCalibre()
590580
{
591581
var runningProcesses = CalibreProcesses
@@ -595,20 +585,21 @@ private void KillCalibre()
595585
if (runningProcesses.Any())
596586
{
597587
var processNames = runningProcesses.Select(p => p.ProcessName).Distinct();
598-
var warningMessage = $"{ResourceStrings.CalibreProcessesRunningRes}\n\n{string.Join("\n", processNames)}\n\n{ResourceStrings.DoYouWantToProceedRes}";
588+
Logger.LogThis($"Terminating Calibre processes: {string.Join(", ", processNames)}", true);
599589

600-
if (MessageBox.Show(warningMessage, ResourceStrings.CalibreRunning2Res, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
590+
foreach (var process in runningProcesses)
601591
{
602-
foreach (var process in runningProcesses)
592+
try
603593
{
604594
process.Kill();
595+
process.WaitForExit(1000); // Wait up to 1 second for the process to exit
596+
}
597+
catch (Exception ex)
598+
{
599+
Logger.LogThis($"Error killing process {process.ProcessName}: {ex.Message}", true);
605600
}
606-
Logger.LogThis("Calibre-related processes were running and have been terminated.", true);
607-
}
608-
else
609-
{
610-
Logger.LogThis("User chose not to terminate Calibre-related processes.", true);
611601
}
602+
Logger.LogThis("Calibre-related processes have been terminated.", true);
612603
}
613604
else
614605
{
@@ -628,9 +619,14 @@ public void ShowSettingsForm()
628619
try
629620
{
630621
Logger.LogThis("Attempting to show Settings form.", true);
622+
623+
// Make sure culture is set correctly before showing the form
624+
CultureManager.SetApplicationCulture();
625+
631626
var form = new SettingsForm();
632627
form.StartPosition = FormStartPosition.CenterScreen;
633628
form.Show();
629+
634630
Logger.LogThis("Settings form displayed successfully.", true);
635631
}
636632
catch (Exception ex)
@@ -666,8 +662,11 @@ public static void Register(Type t)
666662
{
667663
try
668664
{
665+
// Ensure culture is set correctly before displaying any messages
666+
CultureManager.SetApplicationCulture();
667+
669668
Logger.LogThis("Registering shell extension...", true);
670-
KeyRegistryExtensions.RegisterExtension(t.GUID, "ImportToCalibre", GetFileExtensions());
669+
KeyRegistryExtensions.RegisterExtension(t.GUID, "ImportToCalibre", SupportedFileTypes.GetExtensions());
671670
Logger.LogThis("Shell extension registered successfully.", true);
672671
}
673672
catch (Exception ex)
@@ -683,27 +682,30 @@ public static void Unregister(Type t)
683682
{
684683
try
685684
{
685+
// Ensure culture is set correctly before displaying any messages
686+
CultureManager.SetApplicationCulture();
687+
686688
Logger.LogThis("Unregistering shell extension...", true);
687689

688-
KeyRegistryExtensions.UnregisterExtension(t.GUID, GetFileExtensions());
690+
KeyRegistryExtensions.UnregisterExtension(t.GUID, SupportedFileTypes.GetExtensions());
689691
Logger.LogThis("Shell extension unregistered successfully.", true);
690692
}
691693
catch (Exception ex)
692694
{
693695
Logger.LogThis($"Unregistration failed: {ex.Message}");
694696
}
695697
}
696-
697698
}
698699

699-
// Class to represent Calibre library
700+
// Class to represent Calibre library
700701
public class CalibreLibrary
701702
{
702703
public string Path { get; set; }
703704
public string Name { get; set; }
704705
}
705706

706-
// Class to manage registry keys upon registration and unregistration
707+
// Class to manage registry keys upon registration and unregistration.
708+
// Called by [ComRegisterFunction] and [ComUnregisterFunction] in the main class.
707709
public static class KeyRegistryExtensions
708710
{
709711
public static void RegisterExtension(Guid guid, string menuName, List<string> extensions)

CalibreImport/CalibreImport.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
<Compile Include="CalibreImport.cs" />
117117
<Compile Include="CalibreLibraryManager.cs" />
118118
<Compile Include="CheckPortable.cs" />
119+
<Compile Include="CultureManager.cs" />
119120
<Compile Include="CustomSettings.cs" />
120121
<Compile Include="ImportForm.cs">
121122
<SubType>Form</SubType>
@@ -144,6 +145,7 @@
144145
<Compile Include="SettingsForm.Designer.cs">
145146
<DependentUpon>SettingsForm.cs</DependentUpon>
146147
</Compile>
148+
<Compile Include="SupportedFileTypes.cs" />
147149
</ItemGroup>
148150
<!--
149151
Resources for the Forms
@@ -175,7 +177,6 @@
175177
<None Include="Powershell\Post-Build.ps1" />
176178
<None Include="Powershell\Pre-Build.ps1" />
177179
<None Include="Powershell\Setup.ps1" />
178-
<None Include="Properties\CalibreImport.config" />
179180
<None Include="ReleaseFiles\Newtonsoft.Json.dll" />
180181
<None Include="ReleaseFiles\SharpShell.dll" />
181182
<None Include="ReleaseFiles\CalibreImport.dll" />

0 commit comments

Comments
 (0)