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);
 }
Beispiel #7
0
        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);
 }
Beispiel #9
0
        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));
            }
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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));
            }
        }
Beispiel #12
0
        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()}");
        }
Beispiel #13
0
        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();
        }
Beispiel #14
0
 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());
 }
Beispiel #15
0
 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);
            }
        }
Beispiel #17
0
        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()}");
        }
Beispiel #18
0
 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);
        }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        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();
        }
Beispiel #24
0
        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);
            }
        }
Beispiel #25
0
 private void ShutDown()
 {
     ShokoServer.StopWatchingFiles();
     ShokoServer.AniDBDispose();
     ShokoServer.StopHost();
 }
Beispiel #26
0
        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;
            });
        }
Beispiel #27
0
 public ActionResult RemoveMissingFiles(bool removeFromMyList = true)
 {
     ShokoServer.RemoveMissingFiles(removeFromMyList);
     return(Ok());
 }
Beispiel #28
0
 public ActionResult RunImport()
 {
     ShokoServer.RunImport();
     return(Ok());
 }
Beispiel #29
0
 public ActionResult UpdateAllMediaInfo()
 {
     ShokoServer.RefreshAllMediaInfo();
     return(Ok());
 }
Beispiel #30
0
 public ActionResult SyncMyList()
 {
     ShokoServer.SyncMyList();
     return(Ok());
 }