void btnRunImport_Click(object sender, RoutedEventArgs e) { ShokoServer.RunImport(); MessageBox.Show(Commons.Properties.Resources.Server_ImportRunning, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); }
private void CommandBinding_ScanFolder(object sender, ExecutedRoutedEventArgs e) { object obj = e.Parameter; if (obj == null) { return; } try { if (obj.GetType() == typeof(SVR_ImportFolder)) { SVR_ImportFolder fldr = (SVR_ImportFolder)obj; ShokoServer.ScanFolder(fldr.ImportFolderID); MessageBox.Show(Commons.Properties.Resources.Server_ScanFolder, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { Utils.ShowErrorMessage(ex); } }
void btnSyncMyList_Click(object sender, RoutedEventArgs e) { ShokoServer.SyncMyList(); MessageBox.Show(Commons.Properties.Resources.Server_SyncMyList, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); }
private void BtnSyncMedias_Click(object sender, RoutedEventArgs e) { ShokoServer.SyncMedias(); MessageBox.Show(Commons.Properties.Resources.Server_SyncMediasRunning, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); }
void MainWindow_Loaded(object sender, RoutedEventArgs e) { //ServerInfo.Instance.RefreshImportFolders(); if (ServerSettings.MinimizeOnStartup) { MinimizeToTray(); } tabControl1.SelectedIndex = 4; // Settings logger.Info("Clearing Cache..."); Utils.ClearAutoUpdateCache(); if (ServerSettings.FirstRun) { logger.Info("Initializing DB..."); ShokoServer.RunWorkSetupDB(); } ShokoServer.Instance.CheckForUpdates(); ShokoServer.Instance.UpdateAvailable += (s, args) => new UpdateForm { Owner = Instance }.ShowDialog(); }
void btnUpdateMediaInfo_Click(object sender, RoutedEventArgs e) { ShokoServer.RefreshAllMediaInfo(); MessageBox.Show(Commons.Properties.Resources.Serrver_VideoMediaUpdate, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); }
void MainWindow_Loaded(object sender, RoutedEventArgs e) { //ServerInfo.Instance.RefreshImportFolders(); if (ServerSettings.MinimizeOnStartup) { MinimizeToTray(); } tabControl1.SelectedIndex = 6; // setup if (ServerSettings.AniDB_Username.Equals("jonbaby", StringComparison.InvariantCultureIgnoreCase) || ServerSettings.AniDB_Username.Equals("jmediamanager", StringComparison.InvariantCultureIgnoreCase)) { btnUploadAzureCache.Visibility = System.Windows.Visibility.Visible; } logger.Info("Clearing Cache..."); Utils.ClearAutoUpdateCache(); ShowDatabaseSetup(); logger.Info("Initializing DB..."); ShokoServer.RunWorkSetupDB(); ShokoServer.Instance.CheckForUpdates(); ShokoServer.Instance.UpdateAvailable += (s, args) => new UpdateForm { Owner = Instance }.ShowDialog(); }
void btnRemoveMissingFiles_Click(object sender, RoutedEventArgs e) { ShokoServer.RemoveMissingFiles(); MessageBox.Show(Commons.Properties.Resources.Server_RemoveMissingFiles, Commons.Properties.Resources.Success, MessageBoxButton.OK, MessageBoxImage.Information); }
static void Main(string[] args) { for (int x = 0; x < args.Length; x++) { if (args[x].Equals("instance", StringComparison.InvariantCultureIgnoreCase)) { if (x + 1 < args.Length) { ServerSettings.DefaultInstance = args[x + 1]; } } } ServerSettings.LoadSettings(); ServerState.Instance.LoadSettings(); ShokoServer.Instance.StartUpServer(); ShokoServer.RunWorkSetupDB(); bool running = true; ShokoServer.Instance.ServerShutdown += (sender, eventArgs) => running = false; Utils.YesNoRequired += (sender, e) => { e.Cancel = true; }; ShokoService.CmdProcessorGeneral.OnQueueStateChangedEvent += ev => Console.WriteLine($"Queue state change: {ev.QueueState.formatMessage()}"); while (running) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(60)); } }
public SVR_ImportFolder SaveImportFolder(ImportFolder folder) { SVR_ImportFolder ns; if (folder.ImportFolderID > 0) { // update ns = GetByID(folder.ImportFolderID); if (ns == null) { throw new Exception($"Could not find Import Folder ID: {folder.ImportFolderID}"); } } else { // create ns = new SVR_ImportFolder(); } if (string.IsNullOrEmpty(folder.ImportFolderName)) { throw new Exception("Must specify an Import Folder name"); } if (string.IsNullOrEmpty(folder.ImportFolderLocation)) { throw new Exception("Must specify an Import Folder location"); } if (!Directory.Exists(folder.ImportFolderLocation)) { throw new Exception("Cannot find Import Folder location"); } if (folder.ImportFolderID == 0) { SVR_ImportFolder nsTemp = GetByImportLocation(folder.ImportFolderLocation); if (nsTemp != null) { throw new Exception("Another entry already exists for the specified Import Folder location"); } } ns.ImportFolderName = folder.ImportFolderName; ns.ImportFolderLocation = folder.ImportFolderLocation; ns.IsDropDestination = folder.IsDropDestination; ns.IsDropSource = folder.IsDropSource; ns.IsWatched = folder.IsWatched; ns.ImportFolderType = folder.ImportFolderType; Save(ns); Utils.MainThreadDispatch(() => { ServerInfo.Instance.RefreshImportFolders(); }); ShokoServer.StopWatchingFiles(); ShokoServer.StartWatchingFiles(); return(ns); }
static void Main(string[] args) { for (int x = 0; x < args.Length; x++) { if (args[x].Equals("instance", StringComparison.InvariantCultureIgnoreCase)) { if (x + 1 < args.Length) { ServerSettings.DefaultInstance = args[x + 1]; } } } ShokoServer.Instance.InitLogger(); ServerSettings.LoadSettings(); ServerState.Instance.LoadSettings(); ShokoServer.Instance.StartUpServer(); // Ensure that the AniDB socket is initialized. Try to Login, then start the server if successful. ShokoServer.Instance.RestartAniDBSocket(); if (!ServerSettings.Instance.FirstRun) { ShokoServer.RunWorkSetupDB(); } else { logger.Warn("The Server is NOT STARTED. It needs to be configured via webui or the settings.json"); } bool running = true; ShokoServer.Instance.ServerShutdown += (sender, eventArgs) => running = false; Utils.YesNoRequired += (sender, e) => { e.Cancel = true; }; ServerState.Instance.PropertyChanged += (sender, e) => { if (e.PropertyName == "StartupFailedMessage" && ServerState.Instance.StartupFailed) { Console.WriteLine("Startup failed! Error message: " + ServerState.Instance.StartupFailedMessage); } }; ShokoService.CmdProcessorGeneral.OnQueueStateChangedEvent += ev => Console.WriteLine($"Queue state change: {ev.QueueState.formatMessage()}"); while (running) { System.Threading.Thread.Sleep(TimeSpan.FromSeconds(60)); } }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { if (!string.IsNullOrEmpty(Args?.Instance)) { ServerSettings.DefaultInstance = Args.Instance; } ShokoServer.Instance.InitLogger(); ServerSettings.LoadSettings(); ServerState.Instance.LoadSettings(); if (!ShokoServer.Instance.StartUpServer()) { return; } // Ensure that the AniDB socket is initialized. Try to Login, then start the server if successful. ShokoServer.Instance.RestartAniDBSocket(); if (!ServerSettings.Instance.FirstRun) { ShokoServer.RunWorkSetupDB(); } else { Logger.Warn("The Server is NOT STARTED. It needs to be configured via webui or the settings.json"); } ShokoServer.Instance.ServerShutdown += (sender, eventArgs) => AppLifetime.StopApplication(); Utils.YesNoRequired += (sender, e) => { e.Cancel = true; }; ServerState.Instance.PropertyChanged += (sender, e) => { if (e.PropertyName == "StartupFailedMessage" && ServerState.Instance.StartupFailed) { Console.WriteLine("Startup failed! Error message: " + ServerState.Instance.StartupFailedMessage); } }; ShokoService.CmdProcessorGeneral.OnQueueStateChangedEvent += ev => Console.WriteLine($"General Queue state change: {ev.QueueState.formatMessage()}"); }
void MainWindow_Loaded(object sender, RoutedEventArgs e) { //ServerInfo.Instance.RefreshImportFolders(); if (ServerSettings.Instance.MinimizeOnStartup) { MinimizeToTray(); } tabControl1.SelectedIndex = 4; // Settings logger.Info("Clearing Cache..."); Utils.ClearAutoUpdateCache(); if (ServerSettings.Instance.FirstRun || !ShokoService.AnidbProcessor.ValidAniDBCredentials()) { ShokoServer.Instance.RestartAniDBSocket(); if (!ShokoService.AnidbProcessor.Login()) { ShowAniDBLoginDialog(); } while (AniDBLoginOpen) { Thread.Sleep(100); } if (ShokoService.AnidbProcessor.ValidAniDBCredentials()) { logger.Info("Initializing DB..."); ShokoServer.RunWorkSetupDB(); } } ShokoServer.Instance.CheckForUpdates(); ShokoServer.Instance.UpdateAvailable += (s, args) => new UpdateForm { Owner = Instance }.ShowDialog(); }
public ActionResult StartServer() { if (ServerState.Instance.ServerOnline) { return(BadRequest("Already Running")); } if (ServerState.Instance.ServerStarting) { return(BadRequest("Already Starting")); } try { ShokoServer.RunWorkSetupDB(); } catch (Exception e) { logger.Error($"There was an error starting the server: {e}"); return(InternalError($"There was an error starting the server: {e}")); } return(Ok()); }
private object StartServer() { if (ServerState.Instance.ServerOnline) { return(APIStatus.BadRequest("Already Running")); } if (ServerState.Instance.ServerStarting) { return(APIStatus.BadRequest("Already Starting")); } try { ShokoServer.RunWorkSetupDB(); } catch (Exception e) { logger.Error($"There was an error starting the server: {e}"); return(APIStatus.InternalError($"There was an error starting the server: {e}")); } return(APIStatus.OK()); }
void btnImportManualLinks_Click(object sender, RoutedEventArgs e) { if (ShokoServer.IsMyAnime2WorkerBusy()) { MessageBox.Show(Commons.Properties.Resources.Server_Import, Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } txtMA2Progress.Visibility = Visibility.Visible; txtMA2Success.Visibility = Visibility.Visible; Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog { Filter = "Sqlite Files (*.DB3)|*.db3" }; ofd.ShowDialog(); if (!string.IsNullOrEmpty(ofd.FileName)) { ShokoServer.RunMyAnime2Worker(ofd.FileName); } }
private void OnStartup(object a, StartupEventArgs e) { Console.CancelKeyPress += (sender, args) => Dispatcher.Invoke(() => { args.Cancel = true; Shutdown(); }); Icon = new TaskbarIcon(); using (var iconStream = GetResourceStream(new Uri("pack://application:,,,/ShokoServer;component/db.ico")) ?.Stream) { if (iconStream != null) { Icon.Icon = new Icon(iconStream); } } Icon.ToolTipText = "Shoko Server"; ContextMenu menu = new ContextMenu(); MenuItem webui = new MenuItem(); webui.Header = "Open WebUI"; webui.Click += (sender, args) => { try { string IP = GetLocalIPv4(NetworkInterfaceType.Ethernet); if (string.IsNullOrEmpty(IP)) { IP = "127.0.0.1"; } string url = $"http://{IP}:{ServerSettings.Instance.ServerPort}"; OpenUrl(url); } catch (Exception ex) { Logger.Error(ex, ex.ToString()); } }; menu.Items.Add(webui); webui = new MenuItem(); webui.Header = "Exit"; webui.Click += (sender, args) => Dispatcher.Invoke(Shutdown); menu.Items.Add(webui); Icon.ContextMenu = menu; Icon.MenuActivation = PopupActivationMode.All; Icon.Visibility = Visibility.Visible; string instance = null; for (int x = 0; x < e.Args.Length; x++) { if (!e.Args[x].Equals("instance", StringComparison.InvariantCultureIgnoreCase)) { continue; } if (x + 1 >= e.Args.Length) { continue; } instance = e.Args[x + 1]; break; } var arguments = new ProgramArguments { Instance = instance }; if (!string.IsNullOrEmpty(arguments.Instance)) { ServerSettings.DefaultInstance = arguments.Instance; } ShokoServer.Instance.InitLogger(); ServerSettings.LoadSettings(); ServerState.Instance.LoadSettings(); if (!ShokoServer.Instance.StartUpServer()) { return; } // Ensure that the AniDB socket is initialized. Try to Login, then start the server if successful. ShokoServer.Instance.RestartAniDBSocket(); if (!ServerSettings.Instance.FirstRun) { ShokoServer.RunWorkSetupDB(); } else { Logger.Warn("The Server is NOT STARTED. It needs to be configured via webui or the settings.json"); } ShokoServer.Instance.ServerShutdown += (sender, eventArgs) => Shutdown(); Utils.YesNoRequired += (sender, e) => { e.Cancel = true; }; ServerState.Instance.PropertyChanged += (sender, e) => { if (e.PropertyName == "StartupFailedMessage" && ServerState.Instance.StartupFailed) { Console.WriteLine("Startup failed! Error message: " + ServerState.Instance.StartupFailedMessage); } }; ShokoService.CmdProcessorGeneral.OnQueueStateChangedEvent += ev => Console.WriteLine($"General Queue state change: {ev.QueueState.formatMessage()}"); }
public ActionResult SyncAniDBList() { ShokoServer.SyncMyList(); return(APIStatus.OK()); }
// returns false if we should retry private bool MoveFileIfRequired(bool deleteEmpty = true) { // TODO move A LOT of this into renamer helper methods. A renamer can do them optionally if (!ServerSettings.Instance.Import.MoveOnImport) { logger.Trace($"Skipping move of \"{this.FullServerPath}\" as move on import is disabled"); return(true); } // TODO Make this take an argument to disable removing empty dirs. It's slow, and should only be done if needed try { logger.Trace($"Attempting to MOVE file: \"{FullServerPath ?? VideoLocal_Place_ID.ToString()}\""); if (FullServerPath == null) { logger.Error($"Could not find or access the file to move: {VideoLocal_Place_ID}"); return(true); } // check if this file is in the drop folder // otherwise we don't need to move it if (ImportFolder.IsDropSource == 0) { logger.Trace($"Not moving file as it is NOT in the drop folder: \"{FullServerPath}\""); return(true); } if (!File.Exists(FullServerPath)) { logger.Error($"Could not find or access the file to move: \"{FullServerPath}\""); // this can happen due to file locks, so retry return(false); } var sourceFile = new FileInfo(FullServerPath); // find the default destination (var destImpl, string newFolderPath) = RenameFileHelper.GetDestination(this, null); if (!(destImpl is SVR_ImportFolder destFolder)) { // In this case, an error string was returned, but we'll suppress it and give an error elsewhere if (newFolderPath != null) { return(true); } logger.Error($"Could not find a valid destination: \"{FullServerPath}\""); return(true); } // keep the original drop folder for later (take a copy, not a reference) SVR_ImportFolder dropFolder = ImportFolder; if (string.IsNullOrEmpty(newFolderPath)) { return(true); } // We've already resolved FullServerPath, so it doesn't need to be checked string newFilePath = Path.Combine(newFolderPath, Path.GetFileName(FullServerPath)); string newFullServerPath = Path.Combine(destFolder.ImportFolderLocation, newFilePath); var destFullTree = Path.Combine(destFolder.ImportFolderLocation, newFolderPath); if (!Directory.Exists(destFullTree)) { try { Directory.CreateDirectory(destFullTree); } catch (Exception e) { logger.Error(e); return(true); } } // Last ditch effort to ensure we aren't moving a file unto itself if (newFullServerPath.Equals(FullServerPath, StringComparison.InvariantCultureIgnoreCase)) { logger.Error($"Resolved to move \"{newFullServerPath}\" unto itself. NOT MOVING"); return(true); } var originalFileName = FullServerPath; var textStreams = SubtitleHelper.GetSubtitleStreams(this); if (File.Exists(newFullServerPath)) { // A file with the same name exists at the destination. // Handle Duplicate Files, A duplicate file record won't exist yet, // so we'll check the old fashioned way logger.Trace("A file already exists at the new location, checking it for duplicate"); var destVideoLocalPlace = RepoFactory.VideoLocalPlace.GetByFilePathAndImportFolderID(newFilePath, destFolder.ImportFolderID); var destVideoLocal = destVideoLocalPlace?.VideoLocal; if (destVideoLocal == null) { logger.Error("The existing file at the new location does not have a VideoLocal. Not moving"); return(true); } if (destVideoLocal.Hash == VideoLocal.Hash) { logger.Info($"Not moving file as it already exists at the new location, deleting source file instead: \"{FullServerPath}\" --- \"{newFullServerPath}\""); // if the file already exists, we can just delete the source file instead // this is safer than deleting and moving try { sourceFile.Delete(); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{FullServerPath}\" error {e}"); RemoveRecord(false); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource != 1) { return(true); } RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); return(true); } } // Not a dupe, don't delete it logger.Trace("A file already exists at the new location, checking it for version and group"); var destinationExistingAniDBFile = destVideoLocal.GetAniDBFile(); if (destinationExistingAniDBFile == null) { logger.Error("The existing file at the new location does not have AniDB info. Not moving."); return(true); } var aniDBFile = VideoLocal.GetAniDBFile(); if (aniDBFile == null) { logger.Error("The file does not have AniDB info. Not moving."); return(true); } if (destinationExistingAniDBFile.Anime_GroupName == aniDBFile.Anime_GroupName && destinationExistingAniDBFile.FileVersion < aniDBFile.FileVersion) { // This is a V2 replacing a V1 with the same name. // Normally we'd let the Multiple Files Utility handle it, but let's just delete the V1 logger.Info("The existing file is a V1 from the same group. Replacing it."); // Delete the destination (bool success, string _) = destVideoLocalPlace.RemoveAndDeleteFile(); if (!success) { return(false); } // Move ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(false); } // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1 && deleteEmpty) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } } } else { ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(false); } // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1 && deleteEmpty) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } } try { // move any subtitle files foreach (TextStream subtitleFile in textStreams) { if (string.IsNullOrEmpty(subtitleFile.Filename)) { continue; } var newParent = Path.GetDirectoryName(newFullServerPath); var srcParent = Path.GetDirectoryName(originalFileName); if (string.IsNullOrEmpty(newParent) || string.IsNullOrEmpty(srcParent)) { continue; } var subPath = Path.Combine(srcParent, subtitleFile.Filename); if (!File.Exists(subPath)) { continue; } var subFile = new FileInfo(subPath); string newSubPath = Path.Combine(newParent, subFile.Name); if (File.Exists(newSubPath)) { try { File.Delete(newSubPath); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{subtitleFile}\" error {e}"); } } try { subFile.MoveTo(newSubPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{subtitleFile}\" to \"{newSubPath}\" error {e}"); } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } } catch (Exception ex) { logger.Error(ex, $"Could not MOVE file: \"{FullServerPath ?? VideoLocal_Place_ID.ToString()}\" -- {ex}"); } ShokoServer.UnpauseWatchingFiles(); return(true); }
// TODO Merge these, with proper logic depending on the scenario (import, force, etc) public (string, string) MoveWithResultString(string scriptName, bool force = false) { // TODO Make this take an argument to disable removing empty dirs. It's slow, and should only be done if needed if (FullServerPath == null) { logger.Error($"Could not find or access the file to move: {VideoLocal_Place_ID}"); return(string.Empty, "ERROR: Unable to access file"); } if (!File.Exists(FullServerPath)) { logger.Error($"Could not find or access the file to move: \"{FullServerPath}\""); // this can happen due to file locks, so retry return(string.Empty, "ERROR: Could not access the file"); } FileInfo sourceFile = new FileInfo(FullServerPath); // There is a possibility of weird logic based on source of the file. Some handling should be made for it....later (var destImpl, string newFolderPath) = RenameFileHelper.GetDestination(this, scriptName); if (!(destImpl is SVR_ImportFolder destFolder)) { // In this case, an error string was returned, but we'll suppress it and give an error elsewhere if (newFolderPath != null) { logger.Error($"Unable to find destination for: \"{FullServerPath}\""); logger.Error($"The error message was: {newFolderPath}"); return(string.Empty, "ERROR: " + newFolderPath); } logger.Error($"Unable to find destination for: \"{FullServerPath}\""); return(string.Empty, "ERROR: There was an error but no error code returned..."); } // keep the original drop folder for later (take a copy, not a reference) SVR_ImportFolder dropFolder = ImportFolder; if (string.IsNullOrEmpty(newFolderPath)) { logger.Error($"Unable to find destination for: \"{FullServerPath}\""); return(string.Empty, "ERROR: The returned path was null or empty"); } // We've already resolved FullServerPath, so it doesn't need to be checked string newFilePath = Path.Combine(newFolderPath, Path.GetFileName(FullServerPath)); string newFullServerPath = Path.Combine(destFolder.ImportFolderLocation, newFilePath); var destFullTree = Path.Combine(destFolder.ImportFolderLocation, newFolderPath); if (!Directory.Exists(destFullTree)) { try { Directory.CreateDirectory(destFullTree); } catch (Exception e) { logger.Error(e); return(string.Empty, $"ERROR: Unable to create directory tree: \"{destFullTree}\""); } } // Last ditch effort to ensure we aren't moving a file unto itself if (newFullServerPath.Equals(FullServerPath, StringComparison.InvariantCultureIgnoreCase)) { logger.Info($"Moving file SKIPPED! The file is already at its desired location: \"{FullServerPath}\""); return(newFolderPath, string.Empty); } if (File.Exists(newFullServerPath)) { logger.Error($"A file already exists at the desired location: \"{FullServerPath}\""); return(string.Empty, "ERROR: A file already exists at the destination"); } ShokoServer.PauseWatchingFiles(); logger.Info($"Moving file from \"{FullServerPath}\" to \"{newFullServerPath}\""); try { sourceFile.MoveTo(newFullServerPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{FullServerPath}\" to \"{newFullServerPath}\" error {e}"); ShokoServer.UnpauseWatchingFiles(); return(newFullServerPath, "ERROR: " + e); } // Save for later. Scan for subtitles while the vlplace is still set for the source location string originalFileName = FullServerPath; var textStreams = SubtitleHelper.GetSubtitleStreams(this); // Handle Duplicate Files var dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID).ToList(); foreach (var dup in dups) { // Move source if (dup.FilePathFile1.Equals(FilePath) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = newFilePath; dup.ImportFolderIDFile1 = destFolder.ImportFolderID; } else if (dup.FilePathFile2.Equals(FilePath) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = newFilePath; dup.ImportFolderIDFile2 = destFolder.ImportFolderID; } // validate the dup file // There are cases where a dup file was not cleaned up before, so we'll do it here, too if (!dup.GetFullServerPath1() .Equals(dup.GetFullServerPath2(), StringComparison.InvariantCultureIgnoreCase)) { RepoFactory.DuplicateFile.Save(dup); } else { RepoFactory.DuplicateFile.Delete(dup); } } ImportFolderID = destFolder.ImportFolderID; FilePath = newFilePath; RepoFactory.VideoLocalPlace.Save(this); try { // move any subtitle files foreach (TextStream subtitleFile in textStreams) { if (string.IsNullOrEmpty(subtitleFile.Filename)) { continue; } var newParent = Path.GetDirectoryName(newFullServerPath); var srcParent = Path.GetDirectoryName(originalFileName); if (string.IsNullOrEmpty(newParent) || string.IsNullOrEmpty(srcParent)) { continue; } var subPath = Path.Combine(srcParent, subtitleFile.Filename); if (!File.Exists(subPath)) { continue; } var subFile = new FileInfo(subPath); string newSubPath = Path.Combine(newParent, subFile.Name); if (File.Exists(newSubPath)) { try { File.Delete(newSubPath); } catch (Exception e) { logger.Warn($"Unable to DELETE file: \"{subtitleFile}\" error {e}"); } } try { subFile.MoveTo(newSubPath); } catch (Exception e) { logger.Error($"Unable to MOVE file: \"{subtitleFile}\" to \"{newSubPath}\" error {e}"); } } } catch (Exception ex) { logger.Error(ex, ex.ToString()); } // check for any empty folders in drop folder // only for the drop folder if (dropFolder.IsDropSource == 1) { RecursiveDeleteEmptyDirectories(dropFolder?.ImportFolderLocation, true); } ShokoServer.UnpauseWatchingFiles(); return(newFolderPath, string.Empty); }
// returns false if we should try again after the timer // TODO Generify this and Move and make a return model instead of tuple public (bool, string, string) RenameFile(bool preview = false, string scriptName = null) { if (scriptName != null && scriptName.Equals(Shoko.Models.Constants.Renamer.TempFileName)) { return(true, string.Empty, "Error: Do not attempt to use a temp file to rename."); } if (ImportFolder == null) { logger.Error($"Error: The renamer can't get the import folder for ImportFolderID: {ImportFolderID}, File: \"{FilePath}\""); return(true, string.Empty, "Error: Could not find the file"); } string renamed = RenameFileHelper.GetFilename(this, scriptName); if (string.IsNullOrEmpty(renamed)) { logger.Error($"Error: The renamer returned a null or empty name for: \"{FilePath}\""); return(true, string.Empty, "Error: The file renamer returned a null or empty value"); } if (renamed.StartsWith("*Error: ")) { logger.Error($"Error: The renamer returned an error on file: \"{FilePath}\"\n {renamed}"); return(true, string.Empty, renamed.Substring(1)); } // actually rename the file string fullFileName = FullServerPath; // check if the file exists if (string.IsNullOrEmpty(fullFileName)) { logger.Error($"Error could not find the original file for renaming, or it is in use: \"{fullFileName}\""); return(false, renamed, "Error: Could not access the file"); } if (!File.Exists(fullFileName)) { logger.Error($"Error could not find the original file for renaming, or it is in use: \"{fullFileName}\""); return(false, renamed, "Error: Could not access the file"); } // actually rename the file string path = Path.GetDirectoryName(fullFileName); string newFullName = Path.Combine(path, renamed); var textStreams = SubtitleHelper.GetSubtitleStreams(this); try { if (fullFileName.Equals(newFullName, StringComparison.InvariantCultureIgnoreCase)) { logger.Info($"Renaming file SKIPPED! no change From \"{fullFileName}\" to \"{newFullName}\""); return(true, renamed, string.Empty); } if (File.Exists(newFullName)) { logger.Info($"Renaming file SKIPPED! Destination Exists \"{newFullName}\""); return(true, renamed, "Error: The filename already exists"); } if (preview) { return(false, renamed, string.Empty); } ShokoServer.PauseWatchingFiles(); logger.Info($"Renaming file From \"{fullFileName}\" to \"{newFullName}\""); try { var file = new FileInfo(fullFileName); file.MoveTo(newFullName); } catch (Exception e) { logger.Info($"Renaming file FAILED! From \"{fullFileName}\" to \"{newFullName}\" - {e}"); ShokoServer.UnpauseWatchingFiles(); return(false, renamed, "Error: Failed to rename file"); } // Rename external subs! var oldBasename = Path.GetFileNameWithoutExtension(fullFileName); var newBasename = Path.GetFileNameWithoutExtension(renamed); foreach (TextStream sub in textStreams) { if (string.IsNullOrEmpty(sub.Filename)) { continue; } var oldSubPath = Path.Combine(path, sub.Filename); if (!File.Exists(oldSubPath)) { logger.Error($"Unable to rename external subtitle \"{sub.Filename}\". Cannot access the file"); continue; } var newSub = sub.Filename.Replace(oldBasename, newBasename); try { var file = new FileInfo(oldSubPath); file.MoveTo(newSub); } catch (Exception e) { logger.Error($"Unable to rename external subtitle \"{sub.Filename}\" to \"{newSub}\". {e}"); } } logger.Info($"Renaming file SUCCESS! From \"{fullFileName}\" to \"{newFullName}\""); Tuple <SVR_ImportFolder, string> tup = VideoLocal_PlaceRepository.GetFromFullPath(newFullName); if (tup == null) { logger.Error($"Unable to LOCATE file \"{newFullName}\" inside the import folders"); ShokoServer.UnpauseWatchingFiles(); return(false, renamed, "Error: Unable to resolve new path"); } // Before we change all references, remap Duplicate Files List <DuplicateFile> dups = RepoFactory.DuplicateFile.GetByFilePathAndImportFolder(FilePath, ImportFolderID); if (dups != null && dups.Count > 0) { foreach (var dup in dups) { bool dupchanged = false; if (dup.FilePathFile1.Equals(FilePath, StringComparison.InvariantCultureIgnoreCase) && dup.ImportFolderIDFile1 == ImportFolderID) { dup.FilePathFile1 = tup.Item2; dupchanged = true; } else if (dup.FilePathFile2.Equals(FilePath, StringComparison.InvariantCultureIgnoreCase) && dup.ImportFolderIDFile2 == ImportFolderID) { dup.FilePathFile2 = tup.Item2; dupchanged = true; } if (dupchanged) { RepoFactory.DuplicateFile.Save(dup); } } } // Rename hash xrefs var filenameHash = RepoFactory.FileNameHash.GetByHash(VideoLocal.Hash); if (!filenameHash.Any(a => a.FileName.Equals(renamed))) { FileNameHash fnhash = new FileNameHash { DateTimeUpdated = DateTime.Now, FileName = renamed, FileSize = VideoLocal.FileSize, Hash = VideoLocal.Hash }; RepoFactory.FileNameHash.Save(fnhash); } FilePath = tup.Item2; RepoFactory.VideoLocalPlace.Save(this); // just in case VideoLocal.FileName = renamed; RepoFactory.VideoLocal.Save(VideoLocal, false); } catch (Exception ex) { logger.Info($"Renaming file FAILED! From \"{fullFileName}\" to \"{newFullName}\" - {ex.Message}"); logger.Error(ex, ex.ToString()); return(true, string.Empty, $"Error: {ex.Message}"); } ShokoServer.UnpauseWatchingFiles(); return(true, renamed, string.Empty); }
public SVR_ImportFolder SaveImportFolder(ImportFolder folder) { SVR_ImportFolder ns; if (folder.ImportFolderID > 0) { // update ns = GetByID(folder.ImportFolderID); if (ns == null) { throw new Exception($"Could not find Import Folder ID: {folder.ImportFolderID}"); } } else { // create ns = new SVR_ImportFolder(); } if (string.IsNullOrEmpty(folder.ImportFolderName)) { throw new Exception("Must specify an Import Folder name"); } if (string.IsNullOrEmpty(folder.ImportFolderLocation)) { throw new Exception("Must specify an Import Folder location"); } if (folder.CloudID == 0) { folder.CloudID = null; } if (folder.CloudID == null && !Directory.Exists(folder.ImportFolderLocation)) { throw new Exception("Cannot find Import Folder location"); } if (folder.ImportFolderID == 0) { SVR_ImportFolder nsTemp = GetByImportLocation(folder.ImportFolderLocation); if (nsTemp != null) { throw new Exception("Another entry already exists for the specified Import Folder location"); } } if (folder.IsDropDestination == 1 && folder.IsDropSource == 1) { throw new Exception("A folder cannot be a drop source and a drop destination at the same time"); } // check to make sure we don't have multiple drop folders IReadOnlyList <SVR_ImportFolder> allFolders = GetAll(); if (folder.IsDropDestination == 1) { foreach (SVR_ImportFolder imf in allFolders) { if (folder.CloudID == imf.CloudID && imf.IsDropDestination == 1 && (folder.ImportFolderID == 0 || folder.ImportFolderID != imf.ImportFolderID)) { imf.IsDropDestination = 0; Save(imf); } else if (imf.CloudID != folder.CloudID) { if (folder.IsDropSource == 1 && (imf.FolderIsDropDestination || imf.FolderIsDropSource)) { throw new Exception("A drop folders cannot have different file systems"); } if (folder.IsDropDestination == 1 && (imf.FolderIsDropDestination || imf.FolderIsDropSource)) { throw new Exception("A drop folders cannot have different file systems"); } } } } ns.ImportFolderName = folder.ImportFolderName; ns.ImportFolderLocation = folder.ImportFolderLocation; ns.IsDropDestination = folder.IsDropDestination; ns.IsDropSource = folder.IsDropSource; ns.IsWatched = folder.IsWatched; ns.ImportFolderType = folder.ImportFolderType; ns.CloudID = folder.CloudID; Save(ns); Utils.MainThreadDispatch(() => { ServerInfo.Instance.RefreshImportFolders(); }); ShokoServer.StopWatchingFiles(); ShokoServer.StartWatchingFiles(); return(ns); }
public MainWindow() { InitializeComponent(); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(ServerSettings.Instance.Culture); ShokoServer.Instance.OAuthProvider = new AuthProvider(this); if (!ShokoServer.Instance.StartUpServer()) { MessageBox.Show(Commons.Properties.Resources.Server_Running, Commons.Properties.Resources.ShokoServer, MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(0); } //Create an instance of the NotifyIcon Class TippuTrayNotify = new NotifyIcon(); // This icon file needs to be in the bin folder of the application TippuTrayNotify = new NotifyIcon(); Stream iconStream = Application.GetResourceStream(new Uri("pack://application:,,,/ShokoServer;component/db.ico")).Stream; TippuTrayNotify.Icon = new Icon(iconStream); iconStream.Dispose(); //show the Tray Notify IconbtnRemoveMissingFiles.Click TippuTrayNotify.Visible = true; //-- for winforms applications System.Windows.Forms.Application.ThreadException -= UnhandledExceptionManager.ThreadExceptionHandler; System.Windows.Forms.Application.ThreadException += UnhandledExceptionManager.ThreadExceptionHandler; CreateMenus(); ServerState.Instance.DatabaseAvailable = false; ServerState.Instance.ServerOnline = false; ServerState.Instance.BaseImagePath = ImageUtils.GetBaseImagesPath(); Closing += MainWindow_Closing; StateChanged += MainWindow_StateChanged; TippuTrayNotify.MouseDoubleClick += TippuTrayNotify_MouseDoubleClick; btnToolbarShutdown.Click += btnToolbarShutdown_Click; btnHasherPause.Click += btnHasherPause_Click; btnHasherResume.Click += btnHasherResume_Click; btnGeneralPause.Click += btnGeneralPause_Click; btnGeneralResume.Click += btnGeneralResume_Click; btnImagesPause.Click += btnImagesPause_Click; btnImagesResume.Click += btnImagesResume_Click; btnAdminMessages.Click += btnAdminMessages_Click; btnRemoveMissingFiles.Click += btnRemoveMissingFiles_Click; btnRunImport.Click += btnRunImport_Click; btnSyncHashes.Click += BtnSyncHashes_Click; btnSyncMedias.Click += BtnSyncMedias_Click; btnSyncMyList.Click += btnSyncMyList_Click; btnSyncVotes.Click += btnSyncVotes_Click; btnUpdateTvDBInfo.Click += btnUpdateTvDBInfo_Click; btnUpdateAllStats.Click += btnUpdateAllStats_Click; btnSyncTrakt.Click += btnSyncTrakt_Click; btnImportManualLinks.Click += btnImportManualLinks_Click; btnUpdateAniDBInfo.Click += btnUpdateAniDBInfo_Click; btnLaunchWebUI.Click += btnLaunchWebUI_Click; btnUpdateImages.Click += btnUpdateImages_Click; btnUploadAzureCache.Click += btnUploadAzureCache_Click; btnUpdateTraktInfo.Click += BtnUpdateTraktInfo_Click; btnSyncPlex.Click += BtnSyncPlexOn_Click; btnValidateImages.Click += BtnValidateAllImages_Click; Loaded += MainWindow_Loaded; txtServerPort.Text = ServerSettings.Instance.ServerPort.ToString(CultureInfo.InvariantCulture); btnToolbarHelp.Click += btnToolbarHelp_Click; btnApplyServerPort.Click += btnApplyServerPort_Click; btnUpdateMediaInfo.Click += btnUpdateMediaInfo_Click; //StartUp(); cboDatabaseType.Items.Clear(); ShokoServer.Instance.GetSupportedDatabases().ForEach(s => cboDatabaseType.Items.Add(s)); cboDatabaseType.SelectionChanged += cboDatabaseType_SelectionChanged; btnChooseImagesFolder.Click += btnChooseImagesFolder_Click; btnSetDefault.Click += BtnSetDefault_Click; btnSaveDatabaseSettings.Click += btnSaveDatabaseSettings_Click; btnRefreshMSSQLServerList.Click += btnRefreshMSSQLServerList_Click; // btnInstallMSSQLServer.Click += new RoutedEventHandler(btnInstallMSSQLServer_Click); btnMaxOnStartup.Click += toggleMinimizeOnStartup; btnMinOnStartup.Click += toggleMinimizeOnStartup; btnLogs.Click += btnLogs_Click; btnChooseVLCLocation.Click += btnChooseVLCLocation_Click; btnJMMEnableStartWithWindows.Click += btnJMMEnableStartWithWindows_Click; btnJMMDisableStartWithWindows.Click += btnJMMDisableStartWithWindows_Click; btnUpdateAniDBLogin.Click += btnUpdateAniDBLogin_Click; btnHasherClear.Click += btnHasherClear_Click; btnGeneralClear.Click += btnGeneralClear_Click; btnImagesClear.Click += btnImagesClear_Click; //automaticUpdater.MenuItem = mnuCheckForUpdates; ServerState.Instance.LoadSettings(); cboLanguages.SelectionChanged += cboLanguages_SelectionChanged; InitCulture(); Instance = this; if (!ServerSettings.Instance.FirstRun && ShokoService.AnidbProcessor.ValidAniDBCredentials()) { logger.Info("Already been set up... Initializing DB..."); ShokoServer.RunWorkSetupDB(); cboLanguages.IsEnabled = true; } SubscribeEvents(); }
void btnSaveDatabaseSettings_Click(object sender, RoutedEventArgs e) { try { btnSaveDatabaseSettings.IsEnabled = false; cboDatabaseType.IsEnabled = false; btnRefreshMSSQLServerList.IsEnabled = false; if (ServerState.Instance.DatabaseIsSQLite) { ServerSettings.Instance.Database.Type = DatabaseTypes.Sqlite; } else if (ServerState.Instance.DatabaseIsSQLServer) { if (string.IsNullOrEmpty(txtMSSQL_DatabaseName.Text) || string.IsNullOrEmpty(txtMSSQL_Password.Password) || string.IsNullOrEmpty(cboMSSQLServerList.Text) || string.IsNullOrEmpty(txtMSSQL_Username.Text)) { MessageBox.Show(Commons.Properties.Resources.Server_FillOutSettings, Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); txtMSSQL_DatabaseName.Focus(); return; } ServerSettings.Instance.Database.Type = DatabaseTypes.SqlServer; ServerSettings.Instance.Database.Schema = txtMSSQL_DatabaseName.Text; ServerSettings.Instance.Database.Password = txtMSSQL_Password.Password; ServerSettings.Instance.Database.Hostname = cboMSSQLServerList.Text; ServerSettings.Instance.Database.Username = txtMSSQL_Username.Text; } else if (ServerState.Instance.DatabaseIsMySQL) { if (string.IsNullOrEmpty(txtMySQL_DatabaseName.Text) || string.IsNullOrEmpty(txtMySQL_Password.Password) || string.IsNullOrEmpty(txtMySQL_ServerAddress.Text) || string.IsNullOrEmpty(txtMySQL_Username.Text)) { MessageBox.Show(Commons.Properties.Resources.Server_FillOutSettings, Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); txtMySQL_DatabaseName.Focus(); return; } ServerSettings.Instance.Database.Type = DatabaseTypes.MySql; ServerSettings.Instance.Database.Schema = txtMySQL_DatabaseName.Text; ServerSettings.Instance.Database.Password = txtMySQL_Password.Password; ServerSettings.Instance.Database.Hostname = txtMySQL_ServerAddress.Text; ServerSettings.Instance.Database.Username = txtMySQL_Username.Text; } logger.Info("Initializing DB..."); ShokoServer.RunWorkSetupDB(); } catch (Exception ex) { logger.Error(ex, ex.ToString()); MessageBox.Show(Commons.Properties.Resources.Server_FailedToStart + ex.Message, Commons.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); } }
private void ShutDown() { ShokoServer.StopWatchingFiles(); ShokoServer.AniDBDispose(); ShokoServer.StopHost(); }
public void ConfigureServices(IServiceCollection services) { ShokoServer.ConfigureServices(services); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CustomAuthOptions.DefaultScheme; options.DefaultChallengeScheme = CustomAuthOptions.DefaultScheme; }).AddScheme <CustomAuthOptions, CustomAuthHandler>(CustomAuthOptions.DefaultScheme, _ => { }); services.AddAuthorization(auth => { auth.AddPolicy("admin", policy => policy.Requirements.Add(new UserHandler(user => user.IsAdmin == 1))); auth.AddPolicy("init", policy => policy.Requirements.Add(new UserHandler(user => user.JMMUserID == 0 && user.UserName == "init"))); }); services.AddSwaggerGen( options => { // resolve the IApiVersionDescriptionProvider service // note: that we have to build a temporary service provider here because one has not been created yet var provider = services.BuildServiceProvider().GetRequiredService <IApiVersionDescriptionProvider>(); // add a swagger document for each discovered API version // note: you might choose to skip or document deprecated API versions differently foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); } options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme() { Description = "Shoko API Key Header", Name = "apikey", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = "apikey", }); options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ApiKey", }, }, new string[] {} }, }); // add a custom operation filter which sets default values //options.OperationFilter<SwaggerDefaultValues>(); // integrate xml comments //Locate the XML file being generated by ASP.NET... var xmlFile = "Shoko.Server.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); if (File.Exists(xmlPath)) { options.IncludeXmlComments(xmlPath); } foreach (Type type in Loader.Instance.Plugins.Keys) { var assembly = type.Assembly; var location = assembly.Location; var xml = Path.Combine(Path.GetDirectoryName(location), $"{Path.GetFileNameWithoutExtension(location)}.xml"); if (File.Exists(xml)) { options.IncludeXmlComments(xml); //Include the XML comments if it exists. } } options.MapType <v3.Models.Shoko.SeriesType>(() => new OpenApiSchema { Type = "string" }); options.MapType <v3.Models.Shoko.EpisodeType>(() => new OpenApiSchema { Type = "string" }); options.CustomSchemaIds(x => x.FullName); }); services.AddSwaggerGenNewtonsoftSupport(); services.AddSignalR(o => { o.EnableDetailedErrors = true; }); services.AddSingleton <QueueEmitter>(); services.AddSingleton <LegacyAniDBEmitter>(); services.AddSingleton <LoggingEmitter>(); // allow CORS calls from other both local and non-local hosts services.AddCors(options => { options.AddDefaultPolicy( builder => { builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); // this caused issues with auth. https://stackoverflow.com/questions/43574552 var mvc = services.AddMvc(options => { options.EnableEndpointRouting = false; options.AllowEmptyInputInBodyModelBinding = true; foreach (var formatter in options.InputFormatters) { if (formatter.GetType() == typeof(NewtonsoftJsonInputFormatter)) { ((NewtonsoftJsonInputFormatter)formatter).SupportedMediaTypes.Add( MediaTypeHeaderValue.Parse("text/plain")); } } options.Filters.Add(typeof(DatabaseBlockedFilter)); options.Filters.Add(typeof(ServerNotRunningFilter)); EmitEmptyEnumerableInsteadOfNullAttribute.MvcOptions = options; }) .SetCompatibilityVersion(CompatibilityVersion.Version_3_0) .AddNewtonsoftJson(json => { json.SerializerSettings.MaxDepth = 10; json.SerializerSettings.ContractResolver = new OmitEmptyEnumerableResolver { NamingStrategy = new DefaultNamingStrategy() }; json.SerializerSettings.NullValueHandling = NullValueHandling.Include; json.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Populate; json.SerializerSettings.DateFormatString = "yyyy-MM-dd"; }); foreach (Type type in Loader.Instance.Plugins.Keys) { var assembly = type.Assembly; if (assembly == Assembly.GetCallingAssembly()) { continue; //Skip the current assembly, this is implicitly added by ASP. } mvc.AddApplicationPart(assembly).AddControllersAsServices(); } services.AddApiVersioning(o => { o.ReportApiVersions = true; o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = ApiVersion.Default; o.ApiVersionReader = ApiVersionReader.Combine( new QueryStringApiVersionReader(), new HeaderApiVersionReader("api-version"), new ShokoApiReader() ); }); services.AddVersionedApiExplorer(); services.AddResponseCaching(); services.Configure <KestrelServerOptions>(options => { options.AllowSynchronousIO = true; }); }
public ActionResult RemoveMissingFiles(bool removeFromMyList = true) { ShokoServer.RemoveMissingFiles(removeFromMyList); return(Ok()); }
public ActionResult RunImport() { ShokoServer.RunImport(); return(Ok()); }
public ActionResult UpdateAllMediaInfo() { ShokoServer.RefreshAllMediaInfo(); return(Ok()); }
public ActionResult SyncMyList() { ShokoServer.SyncMyList(); return(Ok()); }