/// <summary>
        ///     Get all modules information of specified course from database.
        /// </summary>
        /// <returns>List of modules information of specified course.</returns>
        public List <Module> GetModulesFromDb(string courseName)
        {
            List <Module> list = new List <Module>();

            var cmd = _databaseConnection.CreateCommand();

            cmd.CommandText = @"SELECT Id, Name, Title, AuthorHandle, ModuleIndex
                                FROM Module 
                                WHERE CourseName = @courseName";
            cmd.Parameters.Add(new SQLiteParameter("@courseName", courseName));

            var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                Module module = new Module
                {
                    Id           = reader.GetInt32(reader.GetOrdinal("Id")),
                    AuthorHandle = reader.GetString(reader.GetOrdinal("AuthorHandle")),
                    Name         = reader.GetString(reader.GetOrdinal("Name")),
                    Title        = ReplaceInvalidFileNameChars(reader.GetString(reader.GetOrdinal("Title"))),
                    Index        = reader.GetInt32(reader.GetOrdinal("ModuleIndex"))
                };

                module.Clips = GetClipsFromDb(module.Id, ModuleHash(module.Name, module.AuthorHandle), courseName);
                list.Add(module);
            }

            reader.Close();
            return(list);
        }
        public void DecryptAllVideos(string folderPath, Module module, string outputPath, bool hasTranscript)
        {
            try
            {
                // Get all clips of this module from database
                List <Clip> listClips = module.Clips;

                if (listClips.Count > 0)
                {
                    foreach (Clip clip in listClips)
                    {
                        // Get current path of the encrypted video
                        string currentPath = Path.Combine(folderPath, $"{clip.Name}.psv");
                        if (File.Exists(currentPath))
                        {
                            // Create new path with output folder
                            string newPath = Path.Combine(outputPath, $"{clip.Index + 1:00}. {clip.Title}.mp4");

                            // Init video and get it from iStream
                            var playingFileStream = new VirtualFileStream(currentPath);
                            playingFileStream.Clone(out IStream iStream);

                            string fileName = Path.GetFileName(currentPath);

                            bgwDecrypt.ReportProgress(1,
                                                      new Log {
                                Text = $"Decrypting \"{fileName}\"...", TextColor = Color.Yellow
                            });

                            DecryptVideo(iStream, newPath);
                            if (createSubCheckBox.Checked && hasTranscript)
                            {
                                // Generate transcript file if user ask
                                WriteTranscriptFile(clip, newPath);
                            }

                            bgwDecrypt.ReportProgress(1,
                                                      new Log
                            {
                                Text      = $"\"{Path.GetFileName(newPath)}\" decrypt success.\n",
                                TextColor = Color.Green
                            });
                            playingFileStream.Dispose();
                        }
                        else
                        {
                            bgwDecrypt.ReportProgress(1,
                                                      new Log
                            {
                                Text      = $"File \"{Path.GetFileName(currentPath)}\" cannot be found\n",
                                TextColor = Color.Gray,
                            });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
            }
        }