/// <summary>
        /// Process returns a readonly list of now playing media items, filtered by optional parameters
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Get NowPlayingService instance
            NowPlayingService nowPlayingService = (NowPlayingService)ServiceManager.GetInstance("nowplaying");

            // Ensure service is running
            if (nowPlayingService == null)
            {
                processor.WriteJson(new NowPlayingResponse("NowPlayingService is not running!", null));
                return;
            }

            // Store list of now playing objects
            IList<NowPlaying> nowPlaying = nowPlayingService.Playing;

            // Filter by user name
            if (uri.Parameters.ContainsKey("user"))
            {
                nowPlaying = nowPlaying.Where(x => x.User.UserName == uri.Parameters["user"]).ToList();
            }

            // Filter by client name
            if (uri.Parameters.ContainsKey("client"))
            {
                nowPlaying = nowPlaying.Where(x => x.User.CurrentSession.ClientName == uri.Parameters["client"]).ToList();
            }

            // Return list of now playing items
            processor.WriteJson(new NowPlayingResponse(null, nowPlaying));
            return;
        }
Example #2
0
        /// <summary>
        /// Process returns a new session key for this user upon successful login
        /// <summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            logger.IfInfo(String.Format("Authenticated user, generated new session: [user: {0}, key: {1}]", user.UserName, user.SessionId));

            processor.WriteJson(new LoginResponse(null, user.SessionId));
            return;
        }
        /// <summary>
        /// Process returns a file stream containing album art
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Check for the MusicBrainz ID
            string musicBrainzId = null;
            uri.Parameters.TryGetValue("musicBrainzId", out musicBrainzId);
            if (musicBrainzId == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // Find the music brainz id
            string path = ArtPathForMusicBrainzId(musicBrainzId);
            FileInfo info = new FileInfo(path);
            if (info.Exists)
            {
                DateTime? lastModified = info.LastWriteTimeUtc;
                FileStream stream = new FileStream(path, FileMode.Open);
                processor.WriteFile(stream, 0, stream.Length, HttpHeader.MimeTypeForExtension(".jpg"), null, true, lastModified);

                // Close the file so we don't get sharing violations on future accesses
                stream.Close();
            }
            else
            {
                // If all else fails, error
                processor.WriteErrorHeader();
            }
        }
Example #4
0
        /// <summary>
        /// Process returns a readonly list of now playing media items, filtered by optional parameters
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Get NowPlayingService instance
            NowPlayingService nowPlayingService = (NowPlayingService)ServiceManager.GetInstance("nowplaying");

            // Ensure service is running
            if (nowPlayingService == null)
            {
                processor.WriteJson(new NowPlayingResponse("NowPlayingService is not running!", null));
                return;
            }

            // Store list of now playing objects
            IList <NowPlaying> nowPlaying = nowPlayingService.Playing;

            // Filter by user name
            if (uri.Parameters.ContainsKey("user"))
            {
                nowPlaying = nowPlaying.Where(x => x.User.UserName == uri.Parameters["user"]).ToList();
            }

            // Filter by client name
            if (uri.Parameters.ContainsKey("client"))
            {
                nowPlaying = nowPlaying.Where(x => x.User.CurrentSession.ClientName == uri.Parameters["client"]).ToList();
            }

            // Return list of now playing items
            processor.WriteJson(new NowPlayingResponse(null, nowPlaying));
            return;
        }
        public void LocalPath_IfTheWrappedUriIsRelative_ShouldReturnTheRelativePath()
        {
            const string path       = "Directory";
            var          uriWrapper = new UriWrapper(new Uri(path, UriKind.Relative));

            Assert.AreEqual("/" + path, uriWrapper.LocalPath);
        }
Example #6
0
        /// <summary>
        /// Process returns a new session key for this user upon successful login
        /// <summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            logger.IfInfo(String.Format("Authenticated user, generated new session: [user: {0}, key: {1}]", user.UserName, user.SessionId));

            processor.WriteJson(new LoginResponse(null, user.SessionId));
            return;
        }
Example #7
0
        /// <summary>
        /// Process logs the error, creates a JSON response, and send it back to the user on bad API call
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user, string error)
        {
            logger.Error(error);

            ErrorResponse response = new ErrorResponse(error);
            processor.WriteJson(response);
        }
        /// <summary>
        /// Process returns a file stream containing album art
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Check for the MusicBrainz ID
            string musicBrainzId = null;

            uri.Parameters.TryGetValue("musicBrainzId", out musicBrainzId);
            if (musicBrainzId == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // Find the music brainz id
            string   path = ArtPathForMusicBrainzId(musicBrainzId);
            FileInfo info = new FileInfo(path);

            if (info.Exists)
            {
                DateTime?  lastModified = info.LastWriteTimeUtc;
                FileStream stream       = new FileStream(path, FileMode.Open);
                processor.WriteFile(stream, 0, stream.Length, HttpHeader.MimeTypeForExtension(".jpg"), null, true, lastModified);

                // Close the file so we don't get sharing violations on future accesses
                stream.Close();
            }
            else
            {
                // If all else fails, error
                processor.WriteErrorHeader();
            }
        }
Example #9
0
        /// <summary>
        /// Process returns a JSON response list of folders
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Shortcut to favorites repository
            IFavoriteRepository favoriteRepository = Injection.Kernel.Get <IFavoriteRepository>();

            // Lists of favorites and items associated
            IList <IItem>    items     = new List <IItem>();
            IList <Favorite> favorites = new List <Favorite>();

            // If no action specified, read favorites
            if (uri.Action == null || uri.Action == "read")
            {
                // Get this users's favorites
                favorites = favoriteRepository.FavoritesForUserId((int)user.UserId);

                // Get the items associated with their favorites
                items = favoriteRepository.ItemsForFavorites(favorites);

                // Send response
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // Verify ID present for remaining actions
            if (uri.Id == null)
            {
                processor.WriteJson(new FavoritesResponse("ID required for modifying favorites", null, null));
                return;
            }

            // create - add favorites
            if (uri.Action == "create")
            {
                favoriteRepository.AddFavorite((int)user.UserId, (int)uri.Id, null);
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // delete - remove favorites
            if (uri.Action == "delete")
            {
                // Grab favorite to delete, verify its ownership
                Favorite fav = favoriteRepository.FavoriteForId((int)uri.Id);
                if (fav.FavoriteUserId != user.UserId)
                {
                    processor.WriteJson(new FavoritesResponse("Cannot delete another user's favorite", null, null));
                    return;
                }

                // Remove favorite
                favoriteRepository.DeleteFavorite((int)uri.Id);
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // Invalid action
            processor.WriteJson(new FavoritesResponse("Invalid action specified: " + uri.Action, null, null));
            return;
        }
Example #10
0
        /// <summary>
        /// Process returns a JSON response list of folders
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Shortcut to favorites repository
            IFavoriteRepository favoriteRepository = Injection.Kernel.Get<IFavoriteRepository>();

            // Lists of favorites and items associated
            IList<IItem> items = new List<IItem>();
            IList<Favorite> favorites = new List<Favorite>();

            // If no action specified, read favorites
            if (uri.Action == null || uri.Action == "read")
            {
                // Get this users's favorites
                favorites = favoriteRepository.FavoritesForUserId((int)user.UserId);

                // Get the items associated with their favorites
                items = favoriteRepository.ItemsForFavorites(favorites);

                // Send response
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // Verify ID present for remaining actions
            if (uri.Id == null)
            {
                processor.WriteJson(new FavoritesResponse("ID required for modifying favorites", null, null));
                return;
            }

            // create - add favorites
            if (uri.Action == "create")
            {
                favoriteRepository.AddFavorite((int)user.UserId, (int)uri.Id, null);
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // delete - remove favorites
            if (uri.Action == "delete")
            {
                // Grab favorite to delete, verify its ownership
                Favorite fav = favoriteRepository.FavoriteForId((int)uri.Id);
                if (fav.FavoriteUserId != user.UserId)
                {
                    processor.WriteJson(new FavoritesResponse("Cannot delete another user's favorite", null, null));
                    return;
                }

                // Remove favorite
                favoriteRepository.DeleteFavorite((int)uri.Id);
                processor.WriteJson(new FavoritesResponse(null, items, favorites));
                return;
            }

            // Invalid action
            processor.WriteJson(new FavoritesResponse("Invalid action specified: " + uri.Action, null, null));
            return;
        }
        public void Port_IfTheSchemeIsWellknown_ShouldReturnTheDefaultPort()
        {
            var uriWrapper = new UriWrapper(new Uri("http://localhost", UriKind.Absolute));

            // ReSharper disable PossibleInvalidOperationException
            Assert.AreEqual(80, uriWrapper.Port.Value);
            // ReSharper restore PossibleInvalidOperationException
        }
Example #12
0
        /// <summary>
        /// Process logs the error, creates a JSON response, and send it back to the user on bad API call
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user, string error)
        {
            logger.Error(error);

            ErrorResponse response = new ErrorResponse(error);

            processor.WriteJson(response);
        }
        /// <summary>
        /// Process performs a HLS transcode on a media item
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Verify ID received
            if (uri.Id == null)
            {
                processor.WriteJson(new TranscodeHlsResponse("Missing required parameter 'id'"));
                return;
            }

            try
            {
                // Get the media item associated with this id
                ItemType itemType = Injection.Kernel.Get<IItemRepository>().ItemTypeForItemId((int)uri.Id);
                IMediaItem item = null;
                if (itemType == ItemType.Song)
                {
                    item = Injection.Kernel.Get<ISongRepository>().SongForId((int)uri.Id);
                    logger.IfInfo("HLS transcoding for songs not currently supported");

                    // CURRENTLY DO NOT SUPPORT HLS STREAMING FOR SONGS
                    return;
                }
                else if (itemType == ItemType.Video)
                {
                    item = Injection.Kernel.Get<IVideoRepository>().VideoForId((int)uri.Id);
                    logger.IfInfo("Preparing video stream: " + item.FileName);
                }

                // Return an error if none exists
                if ((item == null) || (!File.Exists(item.FilePath())))
                {
                    processor.WriteJson(new TranscodeHlsResponse("No media item exists with ID: " + (int)uri.Id));
                    return;
                }

                // Generate the playlist file
                string response = null;
                string[] transQualities = uri.Parameters.ContainsKey("transQuality") ? uri.Parameters["transQuality"].Split(',') : new string[] {"Medium"};
                if (transQualities.Length == 1)
                {
                    // This is a single playlist
                    response = this.GeneratePlaylist(item, transQualities[0], uri);
                }
                else
                {
                    // This is a multi playlist
                    response = this.GenerateMultiPlaylist(item, transQualities, uri);
                }

                processor.WriteText(response, "application/x-mpegURL");
                logger.IfInfo("Successfully HLS transcoded file!");
            }
            catch (Exception e)
            {
                logger.Error(e);
            }
        }
        public void GetLeftPart_IfTheWrappedUriIsRelativeAndThePartParameterIsQuery_ShouldReturnThePathAndQuery()
        {
            var uriWrapper = new UriWrapper(new Uri("Directory/Sub-Directory/File.txt?Key=Value#Our-fragment", UriKind.Relative));

            Assert.AreEqual("/Directory/Sub-Directory/File.txt?Key=Value", uriWrapper.GetLeftPart(UriPartial.Query));

            uriWrapper = new UriWrapper(new Uri(string.Empty, UriKind.Relative));
            Assert.AreEqual("/", uriWrapper.GetLeftPart(UriPartial.Query));
        }
        public void GetComponents_Test()
        {
            var uriWrapper = new UriWrapper(new Uri("Directory", UriKind.Relative));

            Assert.AreEqual("/Directory", uriWrapper.GetComponents(UriComponents.AbsoluteUri, UriFormat.Unescaped));
            Assert.AreEqual("/Directory", uriWrapper.GetComponents(UriComponents.AbsoluteUri | UriComponents.Host, UriFormat.Unescaped));
            Assert.IsNull(uriWrapper.GetComponents(UriComponents.Host, UriFormat.Unescaped));
            Assert.IsNull(uriWrapper.GetComponents(UriComponents.Port, UriFormat.Unescaped));
        }
Example #16
0
        /// <summary>
        /// Process performs a HLS transcode on a media item
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Verify ID received
            if (uri.Id == null)
            {
                processor.WriteJson(new TranscodeHlsResponse("Missing required parameter 'id'"));
                return;
            }

            try
            {
                // Get the media item associated with this id
                ItemType   itemType = Injection.Kernel.Get <IItemRepository>().ItemTypeForItemId((int)uri.Id);
                IMediaItem item     = null;
                if (itemType == ItemType.Song)
                {
                    item = Injection.Kernel.Get <ISongRepository>().SongForId((int)uri.Id);
                    logger.IfInfo("HLS transcoding for songs not currently supported");

                    // CURRENTLY DO NOT SUPPORT HLS STREAMING FOR SONGS
                    return;
                }
                else if (itemType == ItemType.Video)
                {
                    item = Injection.Kernel.Get <IVideoRepository>().VideoForId((int)uri.Id);
                    logger.IfInfo("Preparing video stream: " + item.FileName);
                }

                // Return an error if none exists
                if ((item == null) || (!File.Exists(item.FilePath())))
                {
                    processor.WriteJson(new TranscodeHlsResponse("No media item exists with ID: " + (int)uri.Id));
                    return;
                }

                // Generate the playlist file
                string   response       = null;
                string[] transQualities = uri.Parameters.ContainsKey("transQuality") ? uri.Parameters["transQuality"].Split(',') : new string[] { "Medium" };
                if (transQualities.Length == 1)
                {
                    // This is a single playlist
                    response = this.GeneratePlaylist(item, transQualities[0], uri);
                }
                else
                {
                    // This is a multi playlist
                    response = this.GenerateMultiPlaylist(item, transQualities, uri);
                }

                processor.WriteText(response, "application/x-mpegURL");
                logger.IfInfo("Successfully HLS transcoded file!");
            }
            catch (Exception e)
            {
                logger.Error(e);
            }
        }
Example #17
0
        /// <summary>
        /// Process returns a JSON response list of genres
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Generate return lists of folders, songs, videos
            IList <Genre>          listOfGenres     = new List <Genre>();
            IList <Folder>         listOfFolders    = new List <Folder>();
            IList <Artist>         listOfArtists    = new List <Artist>();
            IList <Album>          listOfAlbums     = new List <Album>();
            IList <Song>           listOfSongs      = new List <Song>();
            PairList <string, int> sectionPositions = new PairList <string, int>();

            // ID specified
            if (uri.Id != null)
            {
                // Default: artists
                string type = "artists";
                if (uri.Parameters.ContainsKey("type"))
                {
                    type = uri.Parameters["type"];
                }

                // Get single genre, add it for output
                Genre genre = Injection.Kernel.Get <IGenreRepository>().GenreForId((int)uri.Id);
                listOfGenres.Add(genre);

                switch (type)
                {
                case "folders":
                    listOfFolders = genre.ListOfFolders();
                    break;

                case "albums":
                    listOfAlbums = genre.ListOfAlbums();
                    break;

                case "songs":
                    listOfSongs = genre.ListOfSongs();
                    break;

                case "artists":
                default:
                    listOfArtists = genre.ListOfArtists();
                    break;
                }
            }
            else
            {
                // No id parameter
                listOfGenres     = Injection.Kernel.Get <IGenreRepository>().AllGenres();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List <IGroupingItem>(listOfGenres.Select(c => (IGroupingItem)c)));
            }

            // Return all results
            processor.WriteJson(new GenresResponse(null, listOfGenres, listOfFolders, listOfArtists, listOfAlbums, listOfSongs, sectionPositions));
            return;
        }
Example #18
0
        /// <summary>
        /// Process returns a copy of the media database, and can be used to return SQL deltas to update
        /// the local copy of the media database
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // If ID set, return all queries >= this id
            if (uri.Id != null)
            {
                processor.WriteJson(new DatabaseResponse(null, Injection.Kernel.Get <IDatabase>().QueryLogsSinceId((int)uri.Id)));
                return;
            }

            // No id parameter, so send down the whole backup database
            long   databaseLastQueryId = -1;
            string databaseFileName    = DatabaseBackup.Backup(out databaseLastQueryId);

            // Verify database filename present
            if ((object)databaseFileName == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            try
            {
                // Read in entire database file
                Stream stream      = new FileStream(ServerUtility.RootPath() + databaseFileName, FileMode.Open, FileAccess.Read);
                long   length      = stream.Length;
                int    startOffset = 0;

                // Handle the Range header to start from later in the file if connection interrupted
                if (processor.HttpHeaders.ContainsKey("Range"))
                {
                    string range = (string)processor.HttpHeaders["Range"];
                    string start = range.Split(new char[] { '-', '=' })[1];
                    logger.IfInfo("Connection retried.  Resuming from " + start);
                    startOffset = Convert.ToInt32(start);
                }

                // We send the last query id as a custom header
                IDictionary <string, string> customHeader = new Dictionary <string, string>();
                customHeader["WaveBox-LastQueryId"] = databaseLastQueryId.ToString();

                // Send the database file
                processor.WriteFile(stream, startOffset, length, "application/octet-stream", customHeader, true, new FileInfo(ServerUtility.RootPath() + databaseFileName).LastWriteTimeUtc);
                stream.Close();
            }
            catch
            {
                // Send JSON on error
                processor.WriteJson(new DatabaseResponse("Could not open backup database " + databaseFileName, null));
            }

            return;
        }
Example #19
0
        /// <summary>
        /// Process returns a JSON response list of genres
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Generate return lists of folders, songs, videos
            IList<Genre> listOfGenres = new List<Genre>();
            IList<Folder> listOfFolders = new List<Folder>();
            IList<Artist> listOfArtists = new List<Artist>();
            IList<Album> listOfAlbums = new List<Album>();
            IList<Song> listOfSongs = new List<Song>();
            PairList<string, int> sectionPositions = new PairList<string, int>();

            // ID specified
            if (uri.Id != null)
            {
                // Default: artists
                string type = "artists";
                if (uri.Parameters.ContainsKey("type"))
                {
                    type = uri.Parameters["type"];
                }

                // Get single genre, add it for output
                Genre genre = Injection.Kernel.Get<IGenreRepository>().GenreForId((int)uri.Id);
                listOfGenres.Add(genre);

                switch (type)
                {
                    case "folders":
                        listOfFolders = genre.ListOfFolders();
                        break;
                    case "albums":
                        listOfAlbums = genre.ListOfAlbums();
                        break;
                    case "songs":
                        listOfSongs = genre.ListOfSongs();
                        break;
                    case "artists":
                    default:
                        listOfArtists = genre.ListOfArtists();
                        break;
                }
            }
            else
            {
                // No id parameter
                listOfGenres = Injection.Kernel.Get<IGenreRepository>().AllGenres();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List<IGroupingItem>(listOfGenres.Select(c => (IGroupingItem)c)));
            }

            // Return all results
            processor.WriteJson(new GenresResponse(null, listOfGenres, listOfFolders, listOfArtists, listOfAlbums, listOfSongs, sectionPositions));
            return;
        }
Example #20
0
        /// <summary>
        /// Process returns a copy of the media database, and can be used to return SQL deltas to update
        /// the local copy of the media database
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // If ID set, return all queries >= this id
            if (uri.Id != null)
            {
                processor.WriteJson(new DatabaseResponse(null, Injection.Kernel.Get<IDatabase>().QueryLogsSinceId((int)uri.Id)));
                return;
            }

            // No id parameter, so send down the whole backup database
            long databaseLastQueryId = -1;
            string databaseFileName = DatabaseBackup.Backup(out databaseLastQueryId);

            // Verify database filename present
            if ((object)databaseFileName == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            try
            {
                // Read in entire database file
                Stream stream = new FileStream(ServerUtility.RootPath() + databaseFileName, FileMode.Open, FileAccess.Read);
                long length = stream.Length;
                int startOffset = 0;

                // Handle the Range header to start from later in the file if connection interrupted
                if (processor.HttpHeaders.ContainsKey("Range"))
                {
                    string range = (string)processor.HttpHeaders["Range"];
                    string start = range.Split(new char[]{'-', '='})[1];
                    logger.IfInfo("Connection retried.  Resuming from " + start);
                    startOffset = Convert.ToInt32(start);
                }

                // We send the last query id as a custom header
                IDictionary<string, string> customHeader = new Dictionary<string, string>();
                customHeader["WaveBox-LastQueryId"] = databaseLastQueryId.ToString();

                // Send the database file
                processor.WriteFile(stream, startOffset, length, "application/octet-stream", customHeader, true, new FileInfo(ServerUtility.RootPath() + databaseFileName).LastWriteTimeUtc);
                stream.Close();
            }
            catch
            {
                // Send JSON on error
                processor.WriteJson(new DatabaseResponse("Could not open backup database " + databaseFileName, null));
            }

            return;
        }
Example #21
0
        /// <summary>
        /// Process logs this user out and destroys their current session
        /// <summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Destroy session
            if (user.DeleteSession(user.SessionId))
            {
                logger.IfInfo(String.Format("Logged out user, destroyed session: [user: {0}, key: {1}]", user.UserName, user.SessionId));
                processor.WriteJson(new LogoutResponse(null, user.SessionId));
                return;
            }

            processor.WriteJson(new LogoutResponse("Failed to destroy user session", user.SessionId));
            return;
        }
Example #22
0
        /// <summary>
        /// Process logs this user out and destroys their current session
        /// <summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Destroy session
            if (user.DeleteSession(user.SessionId))
            {
                logger.IfInfo(String.Format("Logged out user, destroyed session: [user: {0}, key: {1}]", user.UserName, user.SessionId));
                processor.WriteJson(new LogoutResponse(null, user.SessionId));
                return;
            }

            processor.WriteJson(new LogoutResponse("Failed to destroy user session", user.SessionId));
            return;
        }
Example #23
0
        /// <summary>
        /// Generate playlist for a single item
        /// </summary>
        private string GeneratePlaylist(IMediaItem item, string transQuality, UriWrapper uri)
        {
            // If duration not set, null!
            if ((object)item.Duration == null)
            {
                return(null);
            }

            // Set default parameters from URL
            string s      = uri.Parameters["s"];
            string id     = uri.Parameters["id"];
            string width  = uri.Parameters.ContainsKey("width") ? uri.Parameters["width"] : null;
            string height = uri.Parameters.ContainsKey("height") ? uri.Parameters["height"] : null;

            // Begin creating M3U playlist
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-TARGETDURATION:10");
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");

            int offset = 0;

            for (int i = (int)item.Duration; i > 0; i -= 10)
            {
                // Calculate the length of this slice
                int seconds = i < 10 ? i : 10;

                // Add the default line
                builder.AppendLine("#EXTINF:" + seconds + ",");
                builder.Append("transcode?s=" + s + "&id=" + id + "&offsetSeconds=" + offset + "&transQuality=" + transQuality + "&lengthSeconds=" + seconds + "&transType=MPEGTS&isDirect=true");

                // Add the optional parameters
                if ((object)width != null)
                {
                    builder.Append("&width=" + width);
                }
                if ((object)height != null)
                {
                    builder.Append("&height=" + height);
                }

                builder.AppendLine();
                offset += seconds;
            }

            // Finalize file
            builder.AppendLine("#EXT-X-ENDLIST");

            return(builder.ToString());
        }
Example #24
0
        /// <summary>
        /// Process returns a JSON response list of folders
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Generate return lists of folders, songs, videos
            IList <Folder>         listOfFolders    = new List <Folder>();
            IList <Song>           listOfSongs      = new List <Song>();
            IList <Video>          listOfVideos     = new List <Video>();
            Folder                 containingFolder = null;
            bool                   recursive        = false;
            PairList <string, int> sectionPositions = new PairList <string, int>();

            // If ID present, return that folder
            if (uri.Id != null)
            {
                // Return the folder for this id
                containingFolder = Injection.Kernel.Get <IFolderRepository>().FolderForId((int)uri.Id);
                listOfFolders    = containingFolder.ListOfSubFolders();

                if (uri.Parameters.ContainsKey("recursiveMedia") && uri.Parameters["recursiveMedia"].IsTrue())
                {
                    recursive = true;
                }

                // Get it, son.
                listOfSongs  = containingFolder.ListOfSongs(recursive);
                listOfVideos = containingFolder.ListOfVideos(recursive);

                // Return all results
                processor.WriteJson(new FoldersResponse(null, containingFolder, listOfFolders, listOfSongs, listOfVideos, sectionPositions));
                return;
            }

            // No id parameter
            if (uri.Parameters.ContainsKey("mediaFolders") && uri.Parameters["mediaFolders"].IsTrue())
            {
                // They asked for the media folders
                listOfFolders = Injection.Kernel.Get <IFolderRepository>().MediaFolders();
            }
            else
            {
                // They didn't ask for media folders, so send top level folders
                listOfFolders    = Injection.Kernel.Get <IFolderRepository>().TopLevelFolders();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List <IGroupingItem>(listOfFolders.Select(c => (IGroupingItem)c)));
            }

            // Return all results
            processor.WriteJson(new FoldersResponse(null, containingFolder, listOfFolders, listOfSongs, listOfVideos, sectionPositions));
            return;
        }
Example #25
0
        /// <summary>
        /// Process returns a JSON response list of folders
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Generate return lists of folders, songs, videos
            IList<Folder> listOfFolders = new List<Folder>();
            IList<Song> listOfSongs = new List<Song>();
            IList<Video> listOfVideos = new List<Video>();
            Folder containingFolder = null;
            bool recursive = false;
            PairList<string, int> sectionPositions = new PairList<string, int>();

            // If ID present, return that folder
            if (uri.Id != null)
            {
                // Return the folder for this id
                containingFolder = Injection.Kernel.Get<IFolderRepository>().FolderForId((int)uri.Id);
                listOfFolders = containingFolder.ListOfSubFolders();

                if (uri.Parameters.ContainsKey("recursiveMedia") && uri.Parameters["recursiveMedia"].IsTrue())
                {
                    recursive = true;
                }

                // Get it, son.
                listOfSongs = containingFolder.ListOfSongs(recursive);
                listOfVideos = containingFolder.ListOfVideos(recursive);

                // Return all results
                processor.WriteJson(new FoldersResponse(null, containingFolder, listOfFolders, listOfSongs, listOfVideos, sectionPositions));
                return;
            }

            // No id parameter
            if (uri.Parameters.ContainsKey("mediaFolders") && uri.Parameters["mediaFolders"].IsTrue())
            {
                // They asked for the media folders
                listOfFolders = Injection.Kernel.Get<IFolderRepository>().MediaFolders();
            }
            else
            {
                // They didn't ask for media folders, so send top level folders
                listOfFolders = Injection.Kernel.Get<IFolderRepository>().TopLevelFolders();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List<IGroupingItem>(listOfFolders.Select(c => (IGroupingItem)c)));
            }

            // Return all results
            processor.WriteJson(new FoldersResponse(null, containingFolder, listOfFolders, listOfSongs, listOfVideos, sectionPositions));
            return;
        }
Example #26
0
        private IList <int> ParseIndexes(UriWrapper uri)
        {
            // Try to get the itemIds
            IList <int> itemIds = new List <int>();

            if (uri.Parameters.ContainsKey("indexes"))
            {
                string[] itemIdStrings = uri.Parameters["indexes"].Split(',');

                foreach (string itemIdString in itemIdStrings)
                {
                    int itemId;
                    if (Int32.TryParse(itemIdString, out itemId))
                    {
                        itemIds.Add(itemId);
                    }
                }
            }

            return(itemIds);
        }
Example #27
0
 /// <summary>
 /// Overload for IApiHandler interface
 /// </summary>
 public void Process(UriWrapper uri, IHttpProcessor processor, User user)
 {
     this.Process(uri, processor, user, "Invalid API call");
 }
Example #28
0
        /// <summary>
        /// Process returns a list of videos from WaveBox
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Return list of videos
            IList<Video> videos = new List<Video>();

            // Check if ID present
            if (uri.Id != null)
            {
                // Add video by ID to the list
                videos.Add(Injection.Kernel.Get<IVideoRepository>().VideoForId((int)uri.Id));
            }
            // Check for a request for range of videos
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new VideosResponse("Parameter 'range' requires a valid, comma-separated character tuple", null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new VideosResponse("Parameter 'range' requires characters which are single alphanumeric values", null));
                    return;
                }

                // Grab range of videos
                videos = Injection.Kernel.Get<IVideoRepository>().RangeVideos(start, end);
            }

            // Check for a request to limit/paginate videos, like SQL
            // Note: can be combined with range or all videos
            if (uri.Parameters.ContainsKey("limit") && uri.Id == null)
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2 )
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null));
                    return;
                }

                // Validate as integers
                int index = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a valid integer start index", null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a non-negative integer start index", null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new VideosResponse("Parameter 'limit' requires a valid integer duration", null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new VideosResponse("Parameter 'limit' requires a non-negative integer duration", null));
                        return;
                    }
                }

                // Check if results list already populated by range
                if (videos.Count > 0)
                {
                    // No duration?  Return just specified number of videos
                    if (duration == Int32.MinValue)
                    {
                        videos = videos.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return videos starting at index, up to count duration
                        videos = videos.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no videos in list, grab directly using model method
                    videos = Injection.Kernel.Get<IVideoRepository>().LimitVideos(index, duration);
                }
            }

            // Finally, if no videos already in list, send the whole list
            if (videos.Count == 0)
            {
                videos = Injection.Kernel.Get<IVideoRepository>().AllVideos();
            }

            // Send it!
            processor.WriteJson(new VideosResponse(null, videos));
            return;
        }
Example #29
0
        /// <summary>
        /// Process returns a JSON response list of playlists
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Generate return lists of playlists, media items in them
            IList<Playlist> listOfPlaylists = new List<Playlist>();
            IList<IMediaItem> listOfMediaItems = new List<IMediaItem>();
            PairList<string, int> sectionPositions = new PairList<string, int>();

            // The playlist to perform actions
            Playlist playlist;

            // Check for playlist creation
            if (uri.Action == "create")
            {
                // Try to get the name
                string name = null;
                if (uri.Parameters.ContainsKey("name"))
                {
                    name = HttpUtility.UrlDecode(uri.Parameters["name"]);
                }

                // Verify non-null name
                if (name == null)
                {
                    processor.WriteJson(new PlaylistsResponse("Parameter 'name' required for playlist creation", null, null, null));
                    return;
                }

                // Verify name not already in use
                playlist = Injection.Kernel.Get<IPlaylistRepository>().PlaylistForName(name);
                if (playlist.ItemId != null)
                {
                    processor.WriteJson(new PlaylistsResponse("Playlist name '" + name + "' already in use", null, null, null));
                    return;
                }

                // Looks like this name is unused, so create the playlist
                playlist.PlaylistName = name;
                playlist.CreatePlaylist();

                // Try to get the itemIds to add them to the playlist if necessary
                IList<int> itemIds = this.ParseItemIds(uri);
                if (itemIds.Count > 0)
                {
                    playlist.AddMediaItems(itemIds);
                }

                listOfMediaItems = playlist.ListOfMediaItems();
                listOfPlaylists.Add(playlist);

                // Return newly created playlist
                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // If not creating playlist, and no ID, return all playlists
            if (uri.Id == null)
            {
                listOfPlaylists = Injection.Kernel.Get<IPlaylistRepository>().AllPlaylists();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List<IGroupingItem>(listOfPlaylists.Select(c => (IGroupingItem)c)));
                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // If ID, return the playlist for this ID
            playlist = Injection.Kernel.Get<IPlaylistRepository>().PlaylistForId((int)uri.Id);
            if (playlist.PlaylistId == null)
            {
                processor.WriteJson(new PlaylistsResponse("Playlist does not exist", null, null, null));
                return;
            }

            // read - default action, list all of the items in a playlist
            if (uri.Action == "read")
            {
                listOfPlaylists.Add(playlist);
                listOfMediaItems = playlist.ListOfMediaItems();

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // add - add items to a playlist
            if (uri.Action == "add")
            {
                // Try to get the itemIds to add them to the playlist if necessary
                IList<int> itemIds = this.ParseItemIds(uri);
                if (itemIds.Count == 0)
                {
                    processor.WriteJson(new PlaylistsResponse("No item IDs found in URL", null, null, null));
                    return;
                }

                // Iterate item IDs
                for (int i = 0; i < itemIds.Count; i++)
                {
                    // Store ID
                    int itemId = itemIds[i];

                    // List of songs
                    IList<IMediaItem> songs = null;

                    // Iterate each item type in the list, adding items
                    switch (Injection.Kernel.Get<IItemRepository>().ItemTypeForItemId(itemId))
                    {
                        case ItemType.Folder:
                            // get all the media items underneath this folder and add them
                            // Use Select instead of ConvertAll: http://stackoverflow.com/questions/1571819/difference-between-select-and-convertall-in-c-sharp
                            songs = Injection.Kernel.Get<IFolderRepository>().FolderForId(itemId).ListOfSongs(true).Select(x => (IMediaItem)x).ToList();
                            playlist.AddMediaItems(songs);
                            break;
                        case ItemType.Artist:
                            songs = Injection.Kernel.Get<IArtistRepository>().ArtistForId(itemId).ListOfSongs().Select(x => (IMediaItem)x).ToList();
                            playlist.AddMediaItems(songs);
                            break;
                        case ItemType.Album:
                            songs = Injection.Kernel.Get<IAlbumRepository>().AlbumForId(itemId).ListOfSongs().Select(x => (IMediaItem)x).ToList();
                            playlist.AddMediaItems(songs);
                            break;
                        case ItemType.Song:
                            playlist.AddMediaItem(Injection.Kernel.Get<ISongRepository>().SongForId(itemId));
                            break;
                        case ItemType.Video:
                            playlist.AddMediaItem(Injection.Kernel.Get<IVideoRepository>().VideoForId(itemId));
                            break;
                        default:
                            processor.WriteJson(new PlaylistsResponse("Invalid item type at index: " + i, null, null, null));
                            return;
                    }
                }

                // Grab everything just put in the playlist
                listOfPlaylists.Add(playlist);
                listOfMediaItems = playlist.ListOfMediaItems();

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // delete - delete a playlist
            if (uri.Action == "delete")
            {
                playlist.DeletePlaylist();
                listOfPlaylists.Add(playlist);

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // insert - insert item in playlist at specified index
            if (uri.Action == "insert")
            {
                IList<int> insertItemIds = this.ParseItemIds(uri);
                IList<int> insertIndexes = this.ParseIndexes(uri);
                if (insertItemIds.Count == 0 || insertItemIds.Count != insertIndexes.Count)
                {
                    processor.WriteJson(new PlaylistsResponse("Incorrect number of items and indices supplied for action 'insert'", null, null, null));
                    return;
                }

                // Add media items and specified indices
                for (int i = 0; i < insertItemIds.Count; i++)
                {
                    int itemId = insertItemIds[i];
                    int index = insertIndexes[i];
                    playlist.InsertMediaItem(itemId, index);
                }

                // Return playlist with media items
                listOfPlaylists.Add(playlist);
                listOfMediaItems = playlist.ListOfMediaItems();

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // move - move an item in the playlist
            if (uri.Action == "move")
            {
                IList<int> moveIndexes = this.ParseIndexes(uri);
                if (moveIndexes.Count == 0 || moveIndexes.Count % 2 != 0)
                {
                    processor.WriteJson(new PlaylistsResponse("Incorrect number of indices supplied for action 'move'", null, null, null));
                    return;
                }

                // Move media items in playlist
                for (int i = 0; i < moveIndexes.Count; i += 2)
                {
                    int fromIndex = moveIndexes[i];
                    int toIndex = moveIndexes[i+1];
                    playlist.MoveMediaItem(fromIndex, toIndex);
                }

                listOfPlaylists.Add(playlist);
                listOfMediaItems = playlist.ListOfMediaItems();

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // remove - remove items from playlist
            if (uri.Action == "remove")
            {
                IList<int> removeIndexes = this.ParseIndexes(uri);
                if (removeIndexes.Count == 0)
                {
                    processor.WriteJson(new PlaylistsResponse("No indices supplied for action 'remove'", null, null, null));
                    return;
                }

                playlist.RemoveMediaItemAtIndexes(removeIndexes);

                listOfPlaylists.Add(playlist);
                listOfMediaItems = playlist.ListOfMediaItems();

                processor.WriteJson(new PlaylistsResponse(null, listOfPlaylists, listOfMediaItems, sectionPositions));
                return;
            }

            // Finally, invalid action supplied
            processor.WriteJson(new PlaylistsResponse("Invalid action: " + uri.Action, listOfPlaylists, listOfMediaItems, sectionPositions));
            return;
        }
Example #30
0
        /// <summary>
        /// Process a Last.fm API request
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Create Last.fm object for this user
            Lastfm lfm = new Lastfm(user);

            // Pull URL parameters for Last.fm integration
            string eve = null;

            uri.Parameters.TryGetValue("event", out eve);

            if (uri.Action == null || uri.Action == "auth")
            {
                // If not authenticated, pass back authorization URL
                if (!lfm.SessionAuthenticated)
                {
                    processor.WriteJson(new ScrobbleResponse(null, lfm.AuthUrl));
                }
                else
                {
                    // Else, already authenticated
                    processor.WriteJson(new ScrobbleResponse("LFMAlreadyAuthenticated"));
                }
                return;
            }

            // If Last.fm is not authenticated, provide an authorization URL
            if (!lfm.SessionAuthenticated)
            {
                logger.IfInfo("You must authenticate before you can scrobble.");

                processor.WriteJson(new ScrobbleResponse("LFMNotAuthenticated", lfm.AuthUrl));
                return;
            }

            // Create list of scrobble data
            IList <LfmScrobbleData> scrobbles = new List <LfmScrobbleData>();

            // Get Last.fm API enumerations
            LfmScrobbleType scrobbleType = Lastfm.ScrobbleTypeForString(uri.Action);

            // On invalid scrobble type, return error JSON
            if (scrobbleType == LfmScrobbleType.INVALID)
            {
                processor.WriteJson(new ScrobbleResponse("LFMInvalidScrobbleType"));
                return;
            }

            // On now playing scrobble type
            if (scrobbleType == LfmScrobbleType.NOWPLAYING)
            {
                // Ensure ID specified for scrobble
                if (uri.Id == null)
                {
                    processor.WriteJson(new ScrobbleResponse("LFMNoIdSpecifiedForNowPlaying"));
                    return;
                }

                // Add successful scrobble to list, submit
                scrobbles.Add(new LfmScrobbleData((int)uri.Id, null));
                lfm.Scrobble(scrobbles, scrobbleType);
            }
            // Else, unknown scrobble event
            else
            {
                // On null event, return error JSON
                if (eve == null)
                {
                    processor.WriteJson(new ScrobbleResponse("LFMNoEventSpecifiedForScrobble"));
                    return;
                }

                // Ensure input is a comma-separated pair
                string[] input = eve.Split(',');
                if ((input.Length % 2) != 0)
                {
                    processor.WriteJson(new ScrobbleResponse("LFMInvalidInput"));
                    return;
                }

                // Add scrobbles from input data pairs
                int i = 0;
                while (i < input.Length)
                {
                    scrobbles.Add(new LfmScrobbleData(int.Parse(input[i]), long.Parse(input[i + 1])));
                    i = i + 2;
                }
            }

            // Scrobble all plays
            string  result = lfm.Scrobble(scrobbles, scrobbleType);
            dynamic resp   = null;

            // No response, service must be offline
            if (result == null)
            {
                processor.WriteJson(new ScrobbleResponse("LFMServiceOffline"));
                return;
            }

            // If result is not null, store deserialize and store it
            try
            {
                resp = JsonConvert.DeserializeObject(result);
            }
            catch (Exception e)
            {
                logger.Error(e);
            }

            // Check for nowplaying or scrobbles fields
            if ((resp.nowplaying != null) || (resp.scrobbles != null))
            {
                // Write blank scrobble response
                processor.WriteJson(new ScrobbleResponse());
                return;
            }
            // Write error JSON if it exists
            else if (resp.error != null)
            {
                processor.WriteJson(new ScrobbleResponse(string.Format("LFM{0}: {1}", resp.error, resp.message)));
                return;
            }
        }
Example #31
0
        /// <summary>
        /// Process generates a JSON list of songs
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Return list of songs
            IList<Song> listOfSongs = new List<Song>();
            PairList<string, int> sectionPositions = new PairList<string, int>();

            // Check for valid ID
            if (uri.Id != null)
            {
                // Add song by ID to the list
                listOfSongs.Add(Injection.Kernel.Get<ISongRepository>().SongForId((int)uri.Id));
            }
            // Check for a request for range of songs
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new SongsResponse("Parameter 'range' requires a valid, comma-separated character tuple", null, null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new SongsResponse("Parameter 'range' requires characters which are single alphanumeric values", null, null));
                    return;
                }

                // Grab range of songs
                listOfSongs = Injection.Kernel.Get<ISongRepository>().RangeSongs(start, end);
            }

            // Check for a request to limit/paginate songs, like SQL
            // Note: can be combined with range or all songs
            if (uri.Parameters.ContainsKey("limit") && uri.Id == null)
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2 )
                {
                    processor.WriteJson(new SongsResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null));
                    return;
                }

                // Validate as integers
                int index = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new SongsResponse("Parameter 'limit' requires a valid integer start index", null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new SongsResponse("Parameter 'limit' requires a non-negative integer start index", null, null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new SongsResponse("Parameter 'limit' requires a valid integer duration", null, null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new SongsResponse("Parameter 'limit' requires a non-negative integer duration", null, null));
                        return;
                    }
                }

                // Check if results list already populated by range
                if (listOfSongs.Count > 0)
                {
                    // No duration?  Return just specified number of songs
                    if (duration == Int32.MinValue)
                    {
                        listOfSongs = listOfSongs.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return songs starting at index, up to count duration
                        listOfSongs = listOfSongs.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no songs in list, grab directly using model method
                    listOfSongs = Injection.Kernel.Get<ISongRepository>().LimitSongs(index, duration);
                }
            }

            // Finally, if no songs already in list, send the whole list
            if (listOfSongs.Count == 0)
            {
                listOfSongs = Injection.Kernel.Get<ISongRepository>().AllSongs();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List<IGroupingItem>(listOfSongs.Select(c => (IGroupingItem)c)));
            }

            // Send it!
            processor.WriteJson(new SongsResponse(null, listOfSongs, sectionPositions));
        }
Example #32
0
        /// <summary>
        /// Process allows the modification of users and their properties
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Return list of users to be passed as JSON
            IList<User> listOfUsers = new List<User>();

            // Parse common parameters
            // Username
            string username = null;
            if (uri.Parameters.ContainsKey("username"))
            {
                username = uri.Parameters["username"];
            }

            // Password
            string password = null;
            if (uri.Parameters.ContainsKey("password"))
            {
                password = uri.Parameters["password"];
            }

            // Role
            Role role = Role.User;
            int roleInt = 0;
            if (uri.Parameters.ContainsKey("role") && Int32.TryParse(uri.Parameters["role"], out roleInt))
            {
                // Validate role
                if (Enum.IsDefined(typeof(Role), roleInt))
                {
                    role = (Role)roleInt;
                }
            }

            // See if we need to make a test user
            if (uri.Parameters.ContainsKey("testUser") && uri.Parameters["testUser"].IsTrue())
            {
                bool success = false;
                int durationSeconds = 0;
                if (uri.Parameters.ContainsKey("durationSeconds"))
                {
                    success = Int32.TryParse(uri.Parameters["durationSeconds"], out durationSeconds);
                }

                // Create a test user and reply with the account info
                User testUser = Injection.Kernel.Get<IUserRepository>().CreateTestUser(success ? (int?)durationSeconds : null);
                if (testUser == null)
                {
                    processor.WriteJson(new UsersResponse("Couldn't create user", listOfUsers));
                    return;
                }

                listOfUsers.Add(testUser);
                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Check for no action, or read action
            if (uri.Action == null || uri.Action == "read")
            {
                // On valid key, return a specific user, and their attributes
                if (uri.Id != null)
                {
                    User oneUser = Injection.Kernel.Get<IUserRepository>().UserForId((int)uri.Id);
                    listOfUsers.Add(oneUser);
                }
                else
                {
                    // Else, return all users
                    listOfUsers = Injection.Kernel.Get<IUserRepository>().AllUsers();
                }

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Perform actions
            // killSession - remove a session by rowId
            if (uri.Action == "killSession")
            {
                // Try to pull rowId from parameters for session management
                int rowId = 0;
                if (!uri.Parameters.ContainsKey("rowId"))
                {
                    processor.WriteJson(new UsersResponse("Missing parameter 'rowId' for action 'killSession'", null));
                    return;
                }

                // Try to parse rowId integer
                if (!Int32.TryParse(uri.Parameters["rowId"], out rowId))
                {
                    processor.WriteJson(new UsersResponse("Invalid integer for 'rowId' for action 'killSession'", null));
                    return;
                }

                // After all checks pass, delete this session, return user associated with it
                var session = Injection.Kernel.Get<ISessionRepository>().SessionForRowId(rowId);
                if (session != null)
                {
                    session.Delete();
                    listOfUsers.Add(Injection.Kernel.Get<IUserRepository>().UserForId(Convert.ToInt32(session.UserId)));
                }

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // create - create a new user
            if (uri.Action == "create")
            {
                // Check for required username and password parameters
                if (username == null || password == null)
                {
                    processor.WriteJson(new UsersResponse("Parameters 'username' and 'password' required for action 'create'", null));
                    return;
                }

                // Attempt to create the user
                User newUser = Injection.Kernel.Get<IUserRepository>().CreateUser(username, password, role, null);
                if (newUser == null)
                {
                    processor.WriteJson(new UsersResponse("Action 'create' failed to create new user", null));
                    return;
                }

                // Verify user didn't already exist
                if (newUser.UserId == null)
                {
                    processor.WriteJson(new UsersResponse("User '" + username + "' already exists!", null));
                    return;
                }

                // Return newly created user
                logger.IfInfo(String.Format("Successfully created new user [id: {0}, username: {1}]", newUser.UserId, newUser.UserName));
                listOfUsers.Add(newUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Verify ID present
            if (uri.Id == null)
            {
                processor.WriteJson(new UsersResponse("Missing parameter ID", null));
                return;
            }

            // delete - remove a user
            if (uri.Action == "delete")
            {
                // Attempt to fetch and delete user
                User deleteUser = Injection.Kernel.Get<IUserRepository>().UserForId((int)uri.Id);
                if (deleteUser.UserName == null || !deleteUser.Delete())
                {
                    processor.WriteJson(new UsersResponse("Action 'delete' failed to delete user", null));
                    return;
                }

                // Return deleted user
                logger.IfInfo(String.Format("Successfully deleted user [id: {0}, username: {1}]", deleteUser.UserId, deleteUser.UserName));
                listOfUsers.Add(deleteUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // update - update a user's username, password, or role
            if (uri.Action == "update")
            {
                // Attempt to get user
                User updateUser = Injection.Kernel.Get<IUserRepository>().UserForId((int)uri.Id);
                if (updateUser.UserName == null)
                {
                    processor.WriteJson(new UsersResponse("Invalid user ID for action 'update'", null));
                    return;
                }

                // If user isn't an admin, verify that they are attempting to update themselves
                if (!user.HasPermission(Role.Admin) && user.UserId != updateUser.UserId)
                {
                    processor.WriteJson(new UsersResponse("Permission denied", null));
                    return;
                }

                // Change username
                if (username != null)
                {
                    if (!updateUser.UpdateUsername(username))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change username", null));
                        return;
                    }
                }

                // Change password
                if (password != null)
                {
                    if (!updateUser.UpdatePassword(password))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change password", null));
                        return;
                    }
                }

                // If user is admin, a role parameter is set, and the role is not their current one, change role
                if (user.HasPermission(Role.Admin) && uri.Parameters.ContainsKey("role") && (role != updateUser.Role))
                {
                    if (!updateUser.UpdateRole(role))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change role", null));
                        return;
                    }
                }

                // Return updated user
                logger.IfInfo(String.Format("Successfully updated user [id: {0}, username: {1}]", updateUser.UserId, updateUser.UserName));
                listOfUsers.Add(updateUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Invalid action
            processor.WriteJson(new UsersResponse("Invalid action specified", null));
            return;
        }
        public void Port_IfTheWrappedUriIsRelative_ShouldReturnNull()
        {
            var uriWrapper = new UriWrapper(new Uri("Directory", UriKind.Relative));

            Assert.IsNull(uriWrapper.Port);
        }
Example #34
0
        /// <summary>
        /// Process returns an AlbumArtistsResponse containing a list of artists, albums, and songs
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Lists of artists, albums, songs to be returned via handler
            IList <AlbumArtist>      albumArtists     = new List <AlbumArtist>();
            IList <Album>            albums           = new List <Album>();
            IList <Song>             songs            = new List <Song>();
            Dictionary <string, int> counts           = new Dictionary <string, int>();
            PairList <string, int>   sectionPositions = new PairList <string, int>();

            // Optional Last.fm info
            string lastfmInfo = null;

            // Check if an ID was passed
            if (uri.Id != null)
            {
                // Add artist by ID to the list
                AlbumArtist a = Injection.Kernel.Get <IAlbumArtistRepository>().AlbumArtistForId((int)uri.Id);
                albumArtists.Add(a);

                // Add artist's albums to response
                albums = a.ListOfAlbums();
                counts.Add("albums", albums.Count);

                // If requested, add artist's songs to response
                if (uri.Parameters.ContainsKey("includeSongs") && uri.Parameters["includeSongs"].IsTrue())
                {
                    songs = a.ListOfSongs();
                    counts.Add("songs", songs.Count);
                }
                else
                {
                    counts.Add("songs", a.ListOfSongs().Count);
                }

                // If requested, add artist's Last.fm info to response
                if (uri.Parameters.ContainsKey("lastfmInfo") && uri.Parameters["lastfmInfo"].IsTrue())
                {
                    logger.IfInfo("Querying Last.fm for artist: " + a.AlbumArtistName);
                    try
                    {
                        lastfmInfo = Lastfm.GetAlbumArtistInfo(a);
                        logger.IfInfo("Last.fm query complete!");
                    }
                    catch (Exception e)
                    {
                        logger.Error("Last.fm query failed!");
                        logger.Error(e);
                    }
                }

                // Get favorites count if available
                if (a.AlbumArtistId != null)
                {
                    int favoriteCount = Injection.Kernel.Get <IFavoriteRepository>().FavoritesForAlbumArtistId(a.AlbumArtistId, user.UserId).Count;
                    counts.Add("favorites", favoriteCount);
                }
                else
                {
                    counts.Add("favorites", 0);
                }
            }
            // Check for a request for range of artists
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new AlbumArtistsResponse("Parameter 'range' requires a valid, comma-separated character tuple", null, null, null, null, null, null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new AlbumArtistsResponse("Parameter 'range' requires characters which are single alphanumeric values", null, null, null, null, null, null));
                    return;
                }

                // Grab range of artists
                albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().RangeAlbumArtists(start, end);
            }

            // Check for a request to limit/paginate artists, like SQL
            // Note: can be combined with range or all artists
            if (uri.Parameters.ContainsKey("limit") && uri.Id == null)
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2)
                {
                    processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null, null, null, null));
                    return;
                }

                // Validate as integers
                int index    = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a valid integer start index", null, null, null, null, null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null, null, null, null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a valid integer duration", null, null, null, null, null, null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null, null, null, null));
                        return;
                    }
                }

                // Check if results list already populated by range
                if (albumArtists.Count > 0)
                {
                    // No duration?  Return just specified number of artists
                    if (duration == Int32.MinValue)
                    {
                        albumArtists = albumArtists.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return artists starting at index, up to count duration
                        albumArtists = albumArtists.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no artists in list, grab directly using model method
                    albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().LimitAlbumArtists(index, duration);
                }
            }

            // Finally, if no artists already in list, send the whole list
            if (albumArtists.Count == 0)
            {
                albumArtists     = Injection.Kernel.Get <IAlbumArtistRepository>().AllAlbumArtists();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List <IGroupingItem>(albumArtists.Select(c => (IGroupingItem)c)));
            }

            // Send it!
            processor.WriteJson(new AlbumArtistsResponse(null, albumArtists, albums, songs, counts, lastfmInfo, sectionPositions));
            return;
        }
Example #35
0
        /// <summary>
        /// Process is used to return a JSON object containing a variety of information about the host system
        /// which is running the WaveBox server
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            try
            {
                // Allocate an array of various statistics about the running process
                IDictionary<string, object> status = new Dictionary<string, object>();

                // Gather data about WaveBox process
                global::System.Diagnostics.Process proc = global::System.Diagnostics.Process.GetCurrentProcess();

                // Get current UNIX time
                long unixTime = DateTime.UtcNow.ToUnixTime();

                // Get current query log ID
                long queryLogId = Injection.Kernel.Get<IDatabase>().LastQueryLogId;

                // Get process ID
                status["pid"] = proc.Id;
                // Get uptime of WaveBox instance
                status["uptime"] = unixTime - WaveBoxService.StartTime.ToUnixTime();
                // Get last update time in UNIX format for status
                status["updated"] = unixTime;
                // Get hostname of machine
                status["hostname"] = System.Environment.MachineName;
                // Get WaveBox version
                status["version"] = WaveBoxService.BuildVersion;
                // Get build date
                status["buildDate"] = WaveBoxService.BuildDate.ToString("MMMM dd, yyyy");
                // Get host platform
                status["platform"] = WaveBoxService.OS.ToDescription();
                // Get current CPU usage
                status["cpuPercent"] = CpuUsage();
                // Get current memory usage in MB
                status["memoryMb"] = (float)proc.WorkingSet64 / 1024f / 1024f;
                // Get peak memory usage in MB
                status["peakMemoryMb"] = (float)proc.PeakWorkingSet64 / 1024f / 1024f;
                // Get list of media types WaveBox can index and serve (removing "Unknown")
                status["mediaTypes"] = Enum.GetNames(typeof(FileType)).Where(x => x != "Unknown").ToList();
                // Get list of transcoders available
                status["transcoders"] = Enum.GetNames(typeof(TranscodeType)).ToList();
                // Get list of services
                status["services"] = ServiceManager.GetServices();
                // Get last query log ID
                status["lastQueryLogId"] = queryLogId;

                // Call for extended status, which uses some database intensive calls
                if (uri.Parameters.ContainsKey("extended"))
                {
                    if (uri.Parameters["extended"].IsTrue())
                    {
                        // Check if any destructive queries have been performed since the last cache
                        if ((statusCache.LastQueryId == null) || (queryLogId > statusCache.LastQueryId))
                        {
                            // Update to the latest query log ID
                            statusCache.LastQueryId = queryLogId;

                            logger.IfInfo("Gathering extended status metrics from database");

                            // Get count of artists
                            statusCache.Cache["artistCount"] = Injection.Kernel.Get<IArtistRepository>().CountArtists();
                            // Get count of album artists
                            statusCache.Cache["albumArtistCount"] = Injection.Kernel.Get<IAlbumArtistRepository>().CountAlbumArtists();
                            // Get count of albums
                            statusCache.Cache["albumCount"] = Injection.Kernel.Get<IAlbumRepository>().CountAlbums();
                            // Get count of songs
                            statusCache.Cache["songCount"] = Injection.Kernel.Get<ISongRepository>().CountSongs();
                            // Get count of videos
                            statusCache.Cache["videoCount"] = Injection.Kernel.Get<IVideoRepository>().CountVideos();
                            // Get total file size of songs (bytes)
                            statusCache.Cache["songFileSize"] = Injection.Kernel.Get<ISongRepository>().TotalSongSize();
                            // Get total file size of videos (bytes)
                            statusCache.Cache["videoFileSize"] = Injection.Kernel.Get<IVideoRepository>().TotalVideoSize();
                            // Get total song duration
                            statusCache.Cache["songDuration"] = Injection.Kernel.Get<ISongRepository>().TotalSongDuration();
                            // Get total video duration
                            statusCache.Cache["videoDuration"] = Injection.Kernel.Get<IVideoRepository>().TotalVideoDuration();

                            logger.IfInfo("Metric gathering complete, cached results!");
                        }

                        // Append cached status dictionary to status
                        status = status.Concat(statusCache.Cache).ToDictionary(x => x.Key, x => x.Value);
                    }
                }

                // Return all status
                processor.WriteJson(new StatusResponse(null, status));
                return;
            }
            catch (Exception e)
            {
                logger.Error(e);
            }

            // Return error
            processor.WriteJson(new StatusResponse("Could not retrieve server status", null));
            return;
        }
Example #36
0
        /// <summary>
        /// Process produces a direct file stream of the requested media file
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Verify ID received
            if (uri.Id == null)
            {
                processor.WriteJson(new StreamResponse("Missing required parameter 'id'"));
                return;
            }

            logger.IfInfo("Starting file streaming sequence");

            // Try to get seconds
            float seconds = 0f;

            if (uri.Parameters.ContainsKey("seconds"))
            {
                float.TryParse(uri.Parameters["seconds"], out seconds);
            }

            try {
                // Get the media item associated with this id
                ItemType   itemType = Injection.Kernel.Get <IItemRepository>().ItemTypeForItemId((int)uri.Id);
                IMediaItem item     = null;
                if (itemType == ItemType.Song)
                {
                    item = Injection.Kernel.Get <ISongRepository>().SongForId((int)uri.Id);
                    logger.IfInfo("Preparing audio stream: " + item.FileName);
                }
                else if (itemType == ItemType.Video)
                {
                    item = Injection.Kernel.Get <IVideoRepository>().VideoForId((int)uri.Id);
                    logger.IfInfo("Preparing video stream: " + item.FileName);
                }

                // Return an error if none exists
                if ((item == null) || (!File.Exists(item.FilePath())))
                {
                    processor.WriteJson(new StreamResponse("No media item exists with ID: " + (int)uri.Id));
                    return;
                }

                // Prepare file stream
                Stream stream      = item.File();
                long   length      = stream.Length;
                int    startOffset = 0;
                long?  limitToSize = null;

                if (seconds > 0)
                {
                    // Guess the file position based on the seconds requested
                    // this is just rough now, but will be improved to take into account the header size
                    float percent = seconds / (float)item.Duration;
                    if (percent < 1f)
                    {
                        startOffset = (int)(item.FileSize * percent);
                        logger.IfInfo("seconds: " + seconds + "  Resuming from " + startOffset);
                    }
                }
                else if (processor.HttpHeaders.ContainsKey("Range"))
                {
                    // Handle the Range header to start from later in the file
                    string range = (string)processor.HttpHeaders["Range"];
                    var    split = range.Split(new char[] { '-', '=' });
                    string start = split[1];
                    string end   = split.Length > 2 ? split[2] : null;

                    logger.IfInfo("Range header: " + range + "  Resuming from " + start);
                    startOffset = Convert.ToInt32(start);
                    if (!ReferenceEquals(end, null) && end != String.Empty)
                    {
                        limitToSize = (Convert.ToInt64(end) + 1) - startOffset;
                    }
                }

                // Send the file
                processor.WriteFile(stream, startOffset, length, item.FileType.MimeType(), null, true, new FileInfo(item.FilePath()).LastWriteTimeUtc, limitToSize);
                stream.Close();

                logger.IfInfo("Successfully streamed file!");
            } catch (Exception e) {
                logger.Error(e);
            }
        }
Example #37
0
        /// <summary>
        /// Process allows the modification of users and their properties
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Return list of users to be passed as JSON
            IList <User> listOfUsers = new List <User>();

            // Parse common parameters
            // Username
            string username = null;

            if (uri.Parameters.ContainsKey("username"))
            {
                username = uri.Parameters["username"];
            }

            // Password
            string password = null;

            if (uri.Parameters.ContainsKey("password"))
            {
                password = uri.Parameters["password"];
            }

            // Role
            Role role    = Role.User;
            int  roleInt = 0;

            if (uri.Parameters.ContainsKey("role") && Int32.TryParse(uri.Parameters["role"], out roleInt))
            {
                // Validate role
                if (Enum.IsDefined(typeof(Role), roleInt))
                {
                    role = (Role)roleInt;
                }
            }

            // See if we need to make a test user
            if (uri.Parameters.ContainsKey("testUser") && uri.Parameters["testUser"].IsTrue())
            {
                bool success         = false;
                int  durationSeconds = 0;
                if (uri.Parameters.ContainsKey("durationSeconds"))
                {
                    success = Int32.TryParse(uri.Parameters["durationSeconds"], out durationSeconds);
                }

                // Create a test user and reply with the account info
                User testUser = Injection.Kernel.Get <IUserRepository>().CreateTestUser(success ? (int?)durationSeconds : null);
                if (testUser == null)
                {
                    processor.WriteJson(new UsersResponse("Couldn't create user", listOfUsers));
                    return;
                }

                listOfUsers.Add(testUser);
                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Check for no action, or read action
            if (uri.Action == null || uri.Action == "read")
            {
                // On valid key, return a specific user, and their attributes
                if (uri.Id != null)
                {
                    User oneUser = Injection.Kernel.Get <IUserRepository>().UserForId((int)uri.Id);
                    listOfUsers.Add(oneUser);
                }
                else
                {
                    // Else, return all users
                    listOfUsers = Injection.Kernel.Get <IUserRepository>().AllUsers();
                }

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Perform actions
            // killSession - remove a session by rowId
            if (uri.Action == "killSession")
            {
                // Try to pull rowId from parameters for session management
                int rowId = 0;
                if (!uri.Parameters.ContainsKey("rowId"))
                {
                    processor.WriteJson(new UsersResponse("Missing parameter 'rowId' for action 'killSession'", null));
                    return;
                }

                // Try to parse rowId integer
                if (!Int32.TryParse(uri.Parameters["rowId"], out rowId))
                {
                    processor.WriteJson(new UsersResponse("Invalid integer for 'rowId' for action 'killSession'", null));
                    return;
                }

                // After all checks pass, delete this session, return user associated with it
                var session = Injection.Kernel.Get <ISessionRepository>().SessionForRowId(rowId);
                if (session != null)
                {
                    session.Delete();
                    listOfUsers.Add(Injection.Kernel.Get <IUserRepository>().UserForId(Convert.ToInt32(session.UserId)));
                }

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // create - create a new user
            if (uri.Action == "create")
            {
                // Check for required username and password parameters
                if (username == null || password == null)
                {
                    processor.WriteJson(new UsersResponse("Parameters 'username' and 'password' required for action 'create'", null));
                    return;
                }

                // Attempt to create the user
                User newUser = Injection.Kernel.Get <IUserRepository>().CreateUser(username, password, role, null);
                if (newUser == null)
                {
                    processor.WriteJson(new UsersResponse("Action 'create' failed to create new user", null));
                    return;
                }

                // Verify user didn't already exist
                if (newUser.UserId == null)
                {
                    processor.WriteJson(new UsersResponse("User '" + username + "' already exists!", null));
                    return;
                }

                // Return newly created user
                logger.IfInfo(String.Format("Successfully created new user [id: {0}, username: {1}]", newUser.UserId, newUser.UserName));
                listOfUsers.Add(newUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Verify ID present
            if (uri.Id == null)
            {
                processor.WriteJson(new UsersResponse("Missing parameter ID", null));
                return;
            }

            // delete - remove a user
            if (uri.Action == "delete")
            {
                // Attempt to fetch and delete user
                User deleteUser = Injection.Kernel.Get <IUserRepository>().UserForId((int)uri.Id);
                if (deleteUser.UserName == null || !deleteUser.Delete())
                {
                    processor.WriteJson(new UsersResponse("Action 'delete' failed to delete user", null));
                    return;
                }

                // Return deleted user
                logger.IfInfo(String.Format("Successfully deleted user [id: {0}, username: {1}]", deleteUser.UserId, deleteUser.UserName));
                listOfUsers.Add(deleteUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // update - update a user's username, password, or role
            if (uri.Action == "update")
            {
                // Attempt to get user
                User updateUser = Injection.Kernel.Get <IUserRepository>().UserForId((int)uri.Id);
                if (updateUser.UserName == null)
                {
                    processor.WriteJson(new UsersResponse("Invalid user ID for action 'update'", null));
                    return;
                }

                // If user isn't an admin, verify that they are attempting to update themselves
                if (!user.HasPermission(Role.Admin) && user.UserId != updateUser.UserId)
                {
                    processor.WriteJson(new UsersResponse("Permission denied", null));
                    return;
                }

                // Change username
                if (username != null)
                {
                    if (!updateUser.UpdateUsername(username))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change username", null));
                        return;
                    }
                }

                // Change password
                if (password != null)
                {
                    if (!updateUser.UpdatePassword(password))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change password", null));
                        return;
                    }
                }

                // If user is admin, a role parameter is set, and the role is not their current one, change role
                if (user.HasPermission(Role.Admin) && uri.Parameters.ContainsKey("role") && (role != updateUser.Role))
                {
                    if (!updateUser.UpdateRole(role))
                    {
                        processor.WriteJson(new UsersResponse("Action 'update' failed to change role", null));
                        return;
                    }
                }

                // Return updated user
                logger.IfInfo(String.Format("Successfully updated user [id: {0}, username: {1}]", updateUser.UserId, updateUser.UserName));
                listOfUsers.Add(updateUser);

                processor.WriteJson(new UsersResponse(null, listOfUsers));
                return;
            }

            // Invalid action
            processor.WriteJson(new UsersResponse("Invalid action specified", null));
            return;
        }
        /// <summary>
        /// Generates multiple item playlist
        /// <summary>
        private string GenerateMultiPlaylist(IMediaItem item, string[] transQualities, UriWrapper uri)
        {
            // Ensure duration is set
            if ((object)item.Duration == null)
            {
                return null;
            }

            // Grab URI parameters
            string s = uri.Parameters["s"];
            string id = uri.Parameters["id"];
            string width = uri.Parameters.ContainsKey("width") ? uri.Parameters["width"] : null;
            string height = uri.Parameters.ContainsKey("height") ? uri.Parameters["height"] : null;

            // Create new string, write M3U header
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");

            // Iterate all transcode qualities
            foreach (string qualityString in transQualities)
            {
                // Get the quality, default to medium
                uint quality = (uint)TranscodeQuality.Medium;
                TranscodeQuality qualityEnum;
                uint qualityValue;

                // First try and parse a word enum value
                if (Enum.TryParse<TranscodeQuality>(qualityString, true, out qualityEnum))
                {
                    quality = (uint)qualityEnum;
                }
                // Otherwise look for a number to use as bitrate
                else if (UInt32.TryParse(qualityString, out qualityValue))
                {
                    quality = qualityValue;
                }
                uint bitrate = VideoTranscoder.DefaultBitrateForQuality(quality);

                // Append information about this transcode to the playlist
                builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + (bitrate * 1000));
                builder.Append("transcodehls?s=" + s + "&id=" + id + "&transQuality=" + bitrate);

                // Add the optional parameters
                if ((object)width != null)
                {
                    builder.Append("&width=" + width);
                }
                if ((object)height != null)
                {
                    builder.Append("&height=" + height);
                }

                builder.AppendLine();
            }

            // Return the completed string
            return builder.ToString();
        }
Example #39
0
        /// <summary>
        /// Process produces a direct file stream of the requested media file
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Verify ID received
            if (uri.Id == null)
            {
                processor.WriteJson(new StreamResponse("Missing required parameter 'id'"));
                return;
            }

            logger.IfInfo("Starting file streaming sequence");

            // Try to get seconds
            float seconds = 0f;
            if (uri.Parameters.ContainsKey("seconds"))
            {
                float.TryParse(uri.Parameters["seconds"], out seconds);
            }

            try
            {
                // Get the media item associated with this id
                ItemType itemType = Injection.Kernel.Get<IItemRepository>().ItemTypeForItemId((int)uri.Id);
                IMediaItem item = null;
                if (itemType == ItemType.Song)
                {
                    item = Injection.Kernel.Get<ISongRepository>().SongForId((int)uri.Id);
                    logger.IfInfo("Preparing audio stream: " + item.FileName);
                }
                else if (itemType == ItemType.Video)
                {
                    item = Injection.Kernel.Get<IVideoRepository>().VideoForId((int)uri.Id);
                    logger.IfInfo("Preparing video stream: " + item.FileName);
                }

                // Return an error if none exists
                if ((item == null) || (!File.Exists(item.FilePath())))
                {
                    processor.WriteJson(new StreamResponse("No media item exists with ID: " + (int)uri.Id));
                    return;
                }

                // Prepare file stream
                Stream stream = item.File();
                long length = stream.Length;
                int startOffset = 0;
                long? limitToSize = null;

                if (seconds > 0)
                {
                    // Guess the file position based on the seconds requested
                    // this is just rough now, but will be improved to take into account the header size
                    float percent = seconds / (float)item.Duration;
                    if (percent < 1f)
                    {
                        startOffset = (int)(item.FileSize * percent);
                        logger.IfInfo("seconds: " + seconds + "  Resuming from " + startOffset);
                    }
                }
                else if (processor.HttpHeaders.ContainsKey("Range"))
                {
                    // Handle the Range header to start from later in the file
                    string range = (string)processor.HttpHeaders["Range"];
                    var split = range.Split(new char[]{'-', '='});
                    string start = split[1];
                    string end = split.Length > 2 ? split[2] : null;

                    logger.IfInfo("Range header: " + range + "  Resuming from " + start);
                    startOffset = Convert.ToInt32(start);
                    if (!ReferenceEquals(end, null) && end != String.Empty)
                    {
                        limitToSize = (Convert.ToInt64(end) + 1) - startOffset;
                    }
                }

                // Send the file
                processor.WriteFile(stream, startOffset, length, item.FileType.MimeType(), null, true, new FileInfo(item.FilePath()).LastWriteTimeUtc, limitToSize);
                stream.Close();

                logger.IfInfo("Successfully streamed file!");
            }
            catch (Exception e)
            {
                logger.Error(e);
            }
        }
Example #40
0
        /// <summary>
        /// Process returns a page from the WaveBox web interface
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Store root path, return index by default
            string path = webRoot;

            // Check for and apply theme path
            if (Injection.Kernel.Get <IServerSettings>().Theme == null)
            {
                logger.Error("No theme set in WaveBox configuration, cannot serve Web UI");

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            // Append theme path to web root
            path += Injection.Kernel.Get <IServerSettings>().Theme;

            // Validate theme path
            if (!Directory.Exists(path))
            {
                logger.Error("Invalid theme '" + Injection.Kernel.Get <IServerSettings>().Theme + "' set in WaveBox configuration, cannot serve Web UI");

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            if (uri.UriParts.Count == 0)
            {
                // No path, so return the home page
                path += Path.DirectorySeparatorChar + "index.html";

                // Ensure theme contains an index
                if (!File.Exists(path))
                {
                    logger.Error("Theme '" + Injection.Kernel.Get <IServerSettings>().Theme + "' missing required file index.html");

                    // File not found
                    processor.WriteErrorHeader();
                    return;
                }
            }
            else
            {
                // Iterate UriParts to send web pages
                for (int i = 0; i < uri.UriParts.Count; i++)
                {
                    string pathPart = uri.UriParts[i];
                    if (pathPart.Length > 0 && pathPart[0] == '.')
                    {
                        // Do not return hidden files/folders
                        processor.WriteErrorHeader();
                        return;
                    }
                    else
                    {
                        path += Path.DirectorySeparatorChar + uri.UriParts[i];
                    }
                }
            }

            // Make sure the file exists
            if (!File.Exists(path))
            {
                logger.IfInfo("File does not exist: " + path);

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            // Serve up files inside html directory
            FileStream file        = new FileStream(path, FileMode.Open, FileAccess.Read);
            int        startOffset = 0;

            // Handle the Range header to start from later in the file
            if (processor.HttpHeaders.ContainsKey("Range"))
            {
                string range = (string)processor.HttpHeaders["Range"];
                string start = range.Split(new char[] { '-', '=' })[1];
                logger.IfInfo("Connection retried.  Resuming from " + start);
                startOffset = Convert.ToInt32(start);
            }

            long length = file.Length - startOffset;

            processor.WriteFile(file, startOffset, length, HttpHeader.MimeTypeForExtension(Path.GetExtension(path)), null, true, new FileInfo(path).LastWriteTimeUtc);
            file.Close();
        }
Example #41
0
        /// <summary>
        /// Process returns a file stream containing album art
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Check for the itemId
            if (uri.Id == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // Check for blur (value between 0 and 100)
            double blurSigma = 0;
            if (uri.Parameters.ContainsKey("blur"))
            {
                int blur = 0;
                Int32.TryParse(uri.Parameters["blur"], out blur);
                if (blur < 0)
                {
                    blur = 0;
                }
                else if (blur > 100)
                {
                    blur = 100;
                }

                blurSigma = (double)blur / 10.0;
            }

            // Grab art stream
            Art art = Injection.Kernel.Get<IArtRepository>().ArtForId((int)uri.Id);
            Stream stream = CreateStream(art);

            // If the stream could not be produced, return error
            if ((object)stream == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // If art size requested...
            if (uri.Parameters.ContainsKey("size"))
            {
                int size = Int32.MaxValue;
                Int32.TryParse(uri.Parameters["size"], out size);

                // Parse size if valid
                if (size != Int32.MaxValue)
                {
                    bool imageMagickFailed = false;
                    if (ServerUtility.DetectOS() != ServerUtility.OS.Windows)
                    {
                        // First try ImageMagick
                        try
                        {
                            Byte[] data = ResizeImageMagick(stream, size, blurSigma);
                            stream = new MemoryStream(data, false);
                        }
                        catch
                        {
                            imageMagickFailed = true;
                        }
                    }

                    // If ImageMagick dll isn't loaded, or this is Windows,
                    if (imageMagickFailed || ServerUtility.DetectOS() == ServerUtility.OS.Windows)
                    {
                        // Resize image, put it in memory stream
                        Image resized = ResizeImageGDI(new Bitmap(stream), new Size(size, size));
                        stream = new MemoryStream();
                        resized.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }
            }

            DateTime? lastModified = null;
            if (!ReferenceEquals(art.LastModified, null))
            {
                lastModified = ((long)art.LastModified).ToDateTime();
            }
            processor.WriteFile(stream, 0, stream.Length, HttpHeader.MimeTypeForExtension(".jpg"), null, true, lastModified);

            // Close the file so we don't get sharing violations on future accesses
            stream.Close();
        }
Example #42
0
        /// <summary>
        /// Process returns a serialized list of albums and songs in JSON format
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // List of songs and albums to be returned via handler
            IList <Song>           songs            = new List <Song>();
            IList <Album>          albums           = new List <Album>();
            PairList <string, int> sectionPositions = new PairList <string, int>();

            // Check if an ID was passed
            if (uri.Id != null)
            {
                // Add album by ID to the list
                Album a = Injection.Kernel.Get <IAlbumRepository>().AlbumForId((int)uri.Id);
                albums.Add(a);

                // Add album's songs to response
                songs = a.ListOfSongs();
            }
            // Check for a request for range of songs
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new AlbumsResponse("Parameter 'range' requires a valid, comma-separated character tuple", null, null, null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new AlbumsResponse("Parameter 'range' requires characters which are single alphanumeric values", null, null, null));
                    return;
                }

                // Grab range of albums
                albums = Injection.Kernel.Get <IAlbumRepository>().RangeAlbums(start, end);
            }

            // Check for a request to limit/paginate songs, like SQL
            // Note: can be combined with range or all albums
            if (uri.Parameters.ContainsKey("limit") && uri.Id == null)
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2)
                {
                    processor.WriteJson(new AlbumsResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null));
                    return;
                }

                // Validate as integers
                int index    = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new AlbumsResponse("Parameter 'limit' requires a valid integer start index", null, null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new AlbumsResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null));

                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new AlbumsResponse("Parameter 'limit' requires a valid integer duration", null, null, null));

                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new AlbumsResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null));

                        return;
                    }
                }

                // Check if results list already populated by range
                if (albums.Count > 0)
                {
                    // No duration?  Return just specified number of albums
                    if (duration == Int32.MinValue)
                    {
                        albums = albums.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return albums starting at index, up to count duration
                        albums = albums.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no albums in list, grab directly using model method
                    albums = Injection.Kernel.Get <IAlbumRepository>().LimitAlbums(index, duration);
                }
            }

            // Finally, if no albums already in list, send the whole list
            if (albums.Count == 0)
            {
                albums           = Injection.Kernel.Get <IAlbumRepository>().AllAlbums();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List <IGroupingItem>(albums.Select(c => (IGroupingItem)c)));
            }

            // Send it!
            processor.WriteJson(new AlbumsResponse(null, albums, songs, sectionPositions));
        }
Example #43
0
        /// <summary>
        /// Process performs a search for a query with specified types
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Lists to return as results
            IList<Artist> artists = new List<Artist>();
            IList<AlbumArtist> albumArtists = new List<AlbumArtist>();
            IList<Album> albums = new List<Album>();
            IList<Song> songs = new List<Song>();
            IList<Video> videos = new List<Video>();

            // If no query is provided, error
            if (!uri.Parameters.ContainsKey("query"))
            {
                processor.WriteJson(new SearchResponse("No search query provided", artists, albumArtists, albums, songs, videos));
                return;
            }

            // URL decode to strip any URL-encoded characters
            string query = HttpUtility.UrlDecode(uri.Parameters["query"]);

            // Ensure query is not blank
            if (query.Length < 1)
            {
                processor.WriteJson(new SearchResponse("Query cannot be empty", artists, albumArtists, albums, songs, videos));
                return;
            }

            // Check for query field
            string field = null;
            if (uri.Parameters.ContainsKey("field"))
            {
                // Use input field for query
                field = HttpUtility.UrlDecode(uri.Parameters["field"]);
            }

            // Check for exact match parameter
            bool exact = false;
            if (uri.Parameters.ContainsKey("exact") && uri.Parameters["exact"].IsTrue())
            {
                exact = true;
            }

            // If a query type is provided...
            if (uri.Parameters.ContainsKey("type"))
            {
                // Iterate all comma-separated values in query type
                foreach (string type in uri.Parameters["type"].Split(','))
                {
                    // Return results, populating lists depending on parameters specified
                    switch (type)
                    {
                        case "artists":
                            artists = Injection.Kernel.Get<IArtistRepository>().SearchArtists(field, query, exact);
                            break;
                        case "albumartists":
                            albumArtists = Injection.Kernel.Get<IAlbumArtistRepository>().SearchAlbumArtists(field, query, exact);
                            break;
                        case "albums":
                            albums = Injection.Kernel.Get<IAlbumRepository>().SearchAlbums(field, query, exact);
                            break;
                        case "songs":
                            songs = Injection.Kernel.Get<ISongRepository>().SearchSongs(field, query, exact);
                            break;
                        case "videos":
                            videos = Injection.Kernel.Get<IVideoRepository>().SearchVideos(field, query, exact);
                            break;
                        default:
                            artists = Injection.Kernel.Get<IArtistRepository>().SearchArtists(field, query, exact);
                            albums = Injection.Kernel.Get<IAlbumRepository>().SearchAlbums(field, query, exact);
                            songs = Injection.Kernel.Get<ISongRepository>().SearchSongs(field, query, exact);
                            videos = Injection.Kernel.Get<IVideoRepository>().SearchVideos(field, query, exact);
                            break;
                    }
                }
            }
            else
            {
                // For no type, provide all types of data
                artists = Injection.Kernel.Get<IArtistRepository>().SearchArtists(field, query, exact);
                albumArtists = Injection.Kernel.Get<IAlbumArtistRepository>().SearchAlbumArtists(field, query, exact);
                albums = Injection.Kernel.Get<IAlbumRepository>().SearchAlbums(field, query, exact);
                songs = Injection.Kernel.Get<ISongRepository>().SearchSongs(field, query, exact);
                videos = Injection.Kernel.Get<IVideoRepository>().SearchVideos(field, query, exact);
            }

            // Check for a request to limit/paginate artists, like SQL
            // Note: can be combined with range or all artists
            if (uri.Parameters.ContainsKey("limit"))
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2)
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null, null, null));
                    return;
                }

                // Validate as integers
                int index = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a valid integer start index", null, null, null, null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null, null, null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new SearchResponse("Parameter 'limit' requires a valid integer duration", null, null, null, null, null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new SearchResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null, null, null));
                        return;
                    }
                }

                // No duration?  Return just specified number of each item
                if (duration == Int32.MinValue)
                {
                    artists = artists.Skip(0).Take(index).ToList();
                    albumArtists = albumArtists.Skip(0).Take(index).ToList();
                    albums = albums.Skip(0).Take(index).ToList();
                    songs = songs.Skip(0).Take(index).ToList();
                    videos = videos.Skip(0).Take(index).ToList();
                }
                else
                {
                    // Else return items starting at index, and taking duration
                    artists = artists.Skip(index).Take(duration).ToList();
                    albumArtists = albumArtists.Skip(index).Take(duration).ToList();
                    albums = albums.Skip(index).Take(duration).ToList();
                    songs = songs.Skip(index).Take(duration).ToList();
                    videos = videos.Skip(index).Take(duration).ToList();
                }
            }

            // Return all results
            processor.WriteJson(new SearchResponse(null, artists, albumArtists, albums, songs, videos));
            return;
        }
Example #44
0
        /// <summary>
        /// Generates multiple item playlist
        /// <summary>
        private string GenerateMultiPlaylist(IMediaItem item, string[] transQualities, UriWrapper uri)
        {
            // Ensure duration is set
            if ((object)item.Duration == null)
            {
                return(null);
            }

            // Grab URI parameters
            string s      = uri.Parameters["s"];
            string id     = uri.Parameters["id"];
            string width  = uri.Parameters.ContainsKey("width") ? uri.Parameters["width"] : null;
            string height = uri.Parameters.ContainsKey("height") ? uri.Parameters["height"] : null;

            // Create new string, write M3U header
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");

            // Iterate all transcode qualities
            foreach (string qualityString in transQualities)
            {
                // Get the quality, default to medium
                uint             quality = (uint)TranscodeQuality.Medium;
                TranscodeQuality qualityEnum;
                uint             qualityValue;

                // First try and parse a word enum value
                if (Enum.TryParse <TranscodeQuality>(qualityString, true, out qualityEnum))
                {
                    quality = (uint)qualityEnum;
                }
                // Otherwise look for a number to use as bitrate
                else if (UInt32.TryParse(qualityString, out qualityValue))
                {
                    quality = qualityValue;
                }
                uint bitrate = VideoTranscoder.DefaultBitrateForQuality(quality);

                // Append information about this transcode to the playlist
                builder.AppendLine("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" + (bitrate * 1000));
                builder.Append("transcodehls?s=" + s + "&id=" + id + "&transQuality=" + bitrate);

                // Add the optional parameters
                if ((object)width != null)
                {
                    builder.Append("&width=" + width);
                }
                if ((object)height != null)
                {
                    builder.Append("&height=" + height);
                }

                builder.AppendLine();
            }

            // Return the completed string
            return(builder.ToString());
        }
Example #45
0
        /// <summary>
        /// Process returns an ArtistsResponse containing a list of artists, albums, and songs
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Lists of artists, albums, songs to be returned via handler
            IList<Artist> artists = new List<Artist>();
            IList<Album> albums = new List<Album>();
            IList<Song> songs = new List<Song>();
            Dictionary<string, int> counts = new Dictionary<string, int>();
            PairList<string, int> sectionPositions = new PairList<string, int>();

            // Optional Last.fm info
            string lastfmInfo = null;

            // Check if an ID was passed
            if (uri.Id != null)
            {
                // Add artist by ID to the list
                Artist a = Injection.Kernel.Get<IArtistRepository>().ArtistForId((int)uri.Id);
                if (a.ArtistId == null)
                {
                    processor.WriteJson(new ArtistsResponse("Artist id not valid", null, null, null, null, null, null));
                    return;
                }

                artists.Add(a);

                // Add artist's albums to response
                albums = a.ListOfAlbums();
                counts.Add("albums", albums.Count);

                // If requested, add artist's songs to response
                if (uri.Parameters.ContainsKey("includeSongs") && uri.Parameters["includeSongs"].IsTrue())
                {
                    songs = a.ListOfSongs();
                    counts.Add("songs", songs.Count);
                }
                else
                {
                    counts.Add("songs", a.ListOfSongs().Count);
                }

                // If requested, add artist's Last.fm info to response
                if (uri.Parameters.ContainsKey("lastfmInfo") && uri.Parameters["lastfmInfo"].IsTrue())
                {
                    logger.IfInfo("Querying Last.fm for artist: " + a.ArtistName);
                    try
                    {
                        lastfmInfo = Lastfm.GetArtistInfo(a);
                        logger.IfInfo("Last.fm query complete!");
                    }
                    catch (Exception e)
                    {
                        logger.Error("Last.fm query failed!");
                        logger.Error(e);
                    }
                }

                // Get favorites count
                int numFavorites = Injection.Kernel.Get<IFavoriteRepository>().FavoritesForArtistId(a.ArtistId, user.UserId).Count;
                counts.Add("favorites", numFavorites);
            }
            // Check for a request for range of artists
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new ArtistsResponse("Parameter 'range' requires a valid, comma-separated character tuple", null, null, null, null, null, null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new ArtistsResponse("Parameter 'range' requires characters which are single alphanumeric values", null, null, null, null, null, null));
                    return;
                }

                // Grab range of artists
                artists = Injection.Kernel.Get<IArtistRepository>().RangeArtists(start, end);
            }

            // Check for a request to limit/paginate artists, like SQL
            // Note: can be combined with range or all artists
            if (uri.Parameters.ContainsKey("limit") && !uri.Parameters.ContainsKey("id"))
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2 )
                {
                    processor.WriteJson(new ArtistsResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null, null, null, null));
                    return;
                }

                // Validate as integers
                int index = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new ArtistsResponse("Parameter 'limit' requires a valid integer start index", null, null, null, null, null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new ArtistsResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null, null, null, null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new ArtistsResponse("Parameter 'limit' requires a valid integer duration", null, null, null, null, null, null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new ArtistsResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null, null, null, null));
                        return;
                    }
                }

                // Check if results list already populated by range
                if (artists.Count > 0)
                {
                    // No duration?  Return just specified number of artists
                    if (duration == Int32.MinValue)
                    {
                        artists = artists.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return artists starting at index, up to count duration
                        artists = artists.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no artists in list, grab directly using model method
                    artists = Injection.Kernel.Get<IArtistRepository>().LimitArtists(index, duration);
                }

            }

            // Finally, if no artists already in list and no ID attribute, send the whole list
            if (artists.Count == 0 && uri.Id == null)
            {
                artists = Injection.Kernel.Get<IArtistRepository>().AllArtists();
                sectionPositions = Utility.SectionPositionsFromSortedList(new List<IGroupingItem>(artists.Select(c => (IGroupingItem)c)));
            }

            // Send it!
            processor.WriteJson(new ArtistsResponse(null, artists, albums, songs, counts, lastfmInfo, sectionPositions));
        }
Example #46
0
        /// <summary>
        /// Process returns a page from the WaveBox web interface
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Store root path, return index by default
            string path = webRoot;

            // Check for and apply theme path
            if (Injection.Kernel.Get<IServerSettings>().Theme == null)
            {
                logger.Error("No theme set in WaveBox configuration, cannot serve Web UI");

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            // Append theme path to web root
            path += Injection.Kernel.Get<IServerSettings>().Theme;

            // Validate theme path
            if (!Directory.Exists(path))
            {
                logger.Error("Invalid theme '" + Injection.Kernel.Get<IServerSettings>().Theme + "' set in WaveBox configuration, cannot serve Web UI");

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            if (uri.UriParts.Count == 0)
            {
                // No path, so return the home page
                path += Path.DirectorySeparatorChar + "index.html";

                // Ensure theme contains an index
                if (!File.Exists(path))
                {
                    logger.Error("Theme '" + Injection.Kernel.Get<IServerSettings>().Theme + "' missing required file index.html");

                    // File not found
                    processor.WriteErrorHeader();
                    return;
                }
            }
            else
            {
                // Iterate UriParts to send web pages
                for (int i = 0; i < uri.UriParts.Count; i++)
                {
                    string pathPart = uri.UriParts[i];
                    if (pathPart.Length > 0 && pathPart[0] == '.')
                    {
                        // Do not return hidden files/folders
                        processor.WriteErrorHeader();
                        return;
                    }
                    else
                    {
                        path += Path.DirectorySeparatorChar + uri.UriParts[i];
                    }
                }
            }

            // Make sure the file exists
            if (!File.Exists(path))
            {
                logger.IfInfo("File does not exist: " + path);

                // File not found
                processor.WriteErrorHeader();
                return;
            }

            // Serve up files inside html directory
            FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read);
            int startOffset = 0;

            // Handle the Range header to start from later in the file
            if (processor.HttpHeaders.ContainsKey("Range"))
            {
                string range = (string)processor.HttpHeaders["Range"];
                string start = range.Split(new char[]{'-', '='})[1];
                logger.IfInfo("Connection retried.  Resuming from " + start);
                startOffset = Convert.ToInt32(start);
            }

            long length = file.Length - startOffset;

            processor.WriteFile(file, startOffset, length, HttpHeader.MimeTypeForExtension(Path.GetExtension(path)), null, true, new FileInfo(path).LastWriteTimeUtc);
            file.Close();
        }
Example #47
0
        /// <summary>
        /// Process returns a file stream containing album art
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Check for the itemId
            if (uri.Id == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // Check for blur (value between 0 and 100)
            double blurSigma = 0;

            if (uri.Parameters.ContainsKey("blur"))
            {
                int blur = 0;
                Int32.TryParse(uri.Parameters["blur"], out blur);
                if (blur < 0)
                {
                    blur = 0;
                }
                else if (blur > 100)
                {
                    blur = 100;
                }

                blurSigma = (double)blur / 10.0;
            }

            // Grab art stream
            Art    art    = Injection.Kernel.Get <IArtRepository>().ArtForId((int)uri.Id);
            Stream stream = CreateStream(art);

            // If the stream could not be produced, return error
            if ((object)stream == null)
            {
                processor.WriteErrorHeader();
                return;
            }

            // If art size requested...
            if (uri.Parameters.ContainsKey("size"))
            {
                int size = Int32.MaxValue;
                Int32.TryParse(uri.Parameters["size"], out size);

                // Parse size if valid
                if (size != Int32.MaxValue)
                {
                    bool imageMagickFailed = false;
                    if (ServerUtility.DetectOS() != ServerUtility.OS.Windows)
                    {
                        // First try ImageMagick
                        try {
                            Byte[] data = ResizeImageMagick(stream, size, blurSigma);
                            stream = new MemoryStream(data, false);
                        } catch {
                            imageMagickFailed = true;
                        }
                    }

                    // If ImageMagick dll isn't loaded, or this is Windows,
                    if (imageMagickFailed || ServerUtility.DetectOS() == ServerUtility.OS.Windows)
                    {
                        // Resize image, put it in memory stream
                        Image resized = ResizeImageGDI(new Bitmap(stream), new Size(size, size));
                        stream = new MemoryStream();
                        resized.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }
            }

            DateTime?lastModified = null;

            if (!ReferenceEquals(art.LastModified, null))
            {
                lastModified = ((long)art.LastModified).ToDateTime();
            }
            processor.WriteFile(stream, 0, stream.Length, HttpHeader.MimeTypeForExtension(".jpg"), null, true, lastModified);

            // Close the file so we don't get sharing violations on future accesses
            stream.Close();
        }
        /// <summary>
        /// Generate playlist for a single item
        /// </summary>
        private string GeneratePlaylist(IMediaItem item, string transQuality, UriWrapper uri)
        {
            // If duration not set, null!
            if ((object)item.Duration == null)
            {
                return null;
            }

            // Set default parameters from URL
            string s = uri.Parameters["s"];
            string id = uri.Parameters["id"];
            string width = uri.Parameters.ContainsKey("width") ? uri.Parameters["width"] : null;
            string height = uri.Parameters.ContainsKey("height") ? uri.Parameters["height"] : null;

            // Begin creating M3U playlist
            StringBuilder builder = new StringBuilder();

            builder.AppendLine("#EXTM3U");
            builder.AppendLine("#EXT-X-TARGETDURATION:10");
            builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");

            int offset = 0;
            for (int i = (int)item.Duration; i > 0; i -= 10)
            {
                // Calculate the length of this slice
                int seconds = i < 10 ? i : 10;

                // Add the default line
                builder.AppendLine("#EXTINF:" + seconds + ",");
                builder.Append("transcode?s=" + s + "&id=" + id + "&offsetSeconds=" + offset + "&transQuality=" + transQuality + "&lengthSeconds=" + seconds + "&transType=MPEGTS&isDirect=true");

                // Add the optional parameters
                if ((object)width != null)
                {
                    builder.Append("&width=" + width);
                }
                if ((object)height != null)
                {
                    builder.Append("&height=" + height);
                }

                builder.AppendLine();
                offset += seconds;
            }

            // Finalize file
            builder.AppendLine("#EXT-X-ENDLIST");

            return builder.ToString();
        }
Example #49
0
        /// <summary>
        /// Process handles the initialization of the file transcoding sequence
        /// <summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Get TranscodeService instance
            TranscodeService transcodeService = (TranscodeService)ServiceManager.GetInstance("transcode");

            // Ensure transcode service is ready
            if ((object)transcodeService == null)
            {
                processor.WriteJson(new TranscodeResponse("TranscodeService is not running!"));
                return;
            }

            // Create transcoder
            ITranscoder transcoder = null;

            // Get seconds offset
            float seconds = 0f;
            if (uri.Parameters.ContainsKey("seconds"))
            {
                float.TryParse(uri.Parameters["seconds"], out seconds);
            }

            // Verify ID received
            if (uri.Id == null)
            {
                processor.WriteJson(new TranscodeResponse("Missing required parameter 'id'"));
                return;
            }

            try
            {
                // Set up default transcoding parameters
                ItemType itemType = Injection.Kernel.Get<IItemRepository>().ItemTypeForItemId((int)uri.Id);
                IMediaItem item = null;
                TranscodeType transType = TranscodeType.MP3;
                bool isDirect = false;
                Stream stream = null;
                int startOffset = 0;
                long? limitToSize = null;
                long length = 0;
                bool estimateContentLength = false;

                // Optionally estimate content length
                if (uri.Parameters.ContainsKey("estimateContentLength"))
                {
                    estimateContentLength = uri.Parameters["estimateContentLength"].IsTrue();
                }

                // Get the media item associated with this id
                if (itemType == ItemType.Song)
                {
                    item = Injection.Kernel.Get<ISongRepository>().SongForId((int)uri.Id);
                    logger.IfInfo("Preparing audio transcode: " + item.FileName);

                    // Default to MP3 transcoding
                    transType = TranscodeType.MP3;
                }
                else if (itemType == ItemType.Video)
                {
                    item = Injection.Kernel.Get<IVideoRepository>().VideoForId((int)uri.Id);
                    logger.IfInfo("Preparing video transcode: " + item.FileName);

                    // Default to h.264 transcoding
                    transType = TranscodeType.X264;
                }

                // Return an error if no item exists
                if ((item == null) || (!File.Exists(item.FilePath())))
                {
                    processor.WriteJson(new TranscodeResponse("No media item exists with ID: " + (int)uri.Id));
                    return;
                }

                // Optionally add isDirect parameter
                if (uri.Parameters.ContainsKey("isDirect"))
                {
                    isDirect = uri.Parameters["isDirect"].IsTrue();
                }

                if (seconds > 0)
                {
                    // Guess the file position based on the seconds requested
                    // this is wrong now, but will be improved to take into account the header size and transcode quality
                    // or even better, we should be able to just pass the offset seconds to ffmpeg
                    float percent = seconds / (float)item.Duration;
                    if (percent < 1f)
                    {
                        startOffset = (int)(item.FileSize * percent);
                        logger.IfInfo("seconds: " + seconds + "  Resuming from " + startOffset);
                    }
                }
                else if (processor.HttpHeaders.ContainsKey("Range"))
                {
                    // Handle the Range header to start from later in the file
                    string range = (string)processor.HttpHeaders["Range"];
                    var split = range.Split(new char[]{'-', '='});
                    string start = split[1];
                    string end = split.Length > 2 ? split[2] : null;
                    logger.IfInfo("Range header: " + range + "  Resuming from " + start + " end: " + end);

                    if (isDirect)
                    {
                        // TODO: Actually implement this lol
                        // This is a direct transfer with no file buffer, so treat a Range request as if it
                        // were start offset, unless an offsetSeconds was specified
                        if (uri.Parameters.ContainsKey("offsetSeconds"))
                        {

                        }
                        else
                        {

                        }
                    }
                    else
                    {
                        // This is a file request so use the range header to specify where in the file to return
                        startOffset = Convert.ToInt32(start);
                        if (!ReferenceEquals(end, null) && end.Length > 0)
                        {
                            limitToSize = (Convert.ToInt64(end) + 1) - startOffset;
                        }
                    }
                }

                // Get the transcoding type if specified
                if (uri.Parameters.ContainsKey("transType"))
                {
                    // Parse transcoding type
                    TranscodeType transTypeTemp;
                    if (Enum.TryParse<TranscodeType>(uri.Parameters["transType"], true, out transTypeTemp))
                    {
                        // Verify this is a valid transcode type for this item type
                        if (transTypeTemp.IsValidForItemType(item.ItemType))
                        {
                            // It is, so use it
                            transType = transTypeTemp;
                        }
                    }
                }

                // Get the quality, default to medium
                uint quality = (uint)TranscodeQuality.Medium;
                if (uri.Parameters.ContainsKey("transQuality"))
                {
                    string qualityString = uri.Parameters["transQuality"];
                    TranscodeQuality qualityEnum;
                    uint qualityValue;
                    // First try and parse a word enum value
                    if (Enum.TryParse<TranscodeQuality>(qualityString, true, out qualityEnum))
                    {
                        quality = (uint)qualityEnum;
                    }
                    // Otherwise look for a number to use as bitrate
                    else if (UInt32.TryParse(qualityString, out qualityValue))
                    {
                        quality = qualityValue;
                    }
                }

                // Create the transcoder
                if (item.ItemType == ItemType.Song)
                {
                    // Begin transcoding song
                    transcoder = transcodeService.TranscodeSong(item, transType, (uint)quality, isDirect, 0, (uint)item.Duration);
                }
                else
                {
                    // Video transcoding is just a bit more complicated.
                    // Check to see if the width, height, and maintainAspect options were used
                    uint? width = null;
                    if (uri.Parameters.ContainsKey("width"))
                    {
                        uint widthTemp;
                        width = UInt32.TryParse(uri.Parameters["width"], out widthTemp) ? (uint?)widthTemp : null;
                    }

                    uint? height = 0;
                    if (uri.Parameters.ContainsKey("height"))
                    {
                        uint heightTemp;
                        height = UInt32.TryParse(uri.Parameters["height"], out heightTemp) ? (uint?)heightTemp : null;
                    }

                    bool maintainAspect = true;
                    if (uri.Parameters.ContainsKey("maintainAspect"))
                    {
                        if (!Boolean.TryParse(uri.Parameters["maintainAspect"], out maintainAspect))
                        {
                            maintainAspect = true;
                        }
                    }

                    // Check for offset seconds and length seconds parameters
                    uint offsetSeconds = 0;
                    if (uri.Parameters.ContainsKey("offsetSeconds"))
                    {
                        UInt32.TryParse(uri.Parameters["offsetSeconds"], out offsetSeconds);
                    }

                    uint lengthSeconds = 0;
                    if (uri.Parameters.ContainsKey("lengthSeconds"))
                    {
                        UInt32.TryParse(uri.Parameters["lengthSeconds"], out lengthSeconds);
                    }

                    // Either stream the rest of the file, or the duration specified
                    lengthSeconds = lengthSeconds == 0 ? (uint)item.Duration - offsetSeconds : lengthSeconds;

                    // Begin video transcoding
                    transcoder = transcodeService.TranscodeVideo(item, transType, quality, isDirect, width, height, maintainAspect, offsetSeconds, lengthSeconds);
                }

                // If a transcoder was generated...
                if ((object)transcoder != null)
                {
                    length = (long)transcoder.EstimatedOutputSize;

                    // Wait up 5 seconds for file or basestream to appear
                    for (int i = 0; i < 20; i++)
                    {
                        if (transcoder.IsDirect)
                        {
                            logger.IfInfo("Checking if base stream exists");
                            if ((object)transcoder.TranscodeProcess != null && (object)transcoder.TranscodeProcess.StandardOutput.BaseStream != null)
                            {
                                // The base stream exists, so the transcoding process has started
                                logger.IfInfo("Base stream exists, starting transfer");
                                stream = transcoder.TranscodeProcess.StandardOutput.BaseStream;
                                break;
                            }
                        }
                        else
                        {
                            logger.IfInfo("Checking if file exists (" + transcoder.OutputPath + ")");
                            if (File.Exists(transcoder.OutputPath))
                            {
                                // The file exists, so the transcoding process has started
                                stream = new FileStream(transcoder.OutputPath, FileMode.Open, FileAccess.Read);
                                break;
                            }
                        }
                        Thread.Sleep(250);
                    }
                }

                // Send the file if either there is no transcoder and the original file exists OR
                // it's a direct transcoder and the base stream exists OR
                // it's a file transcoder and the transcoded file exists
                if ((object)transcoder == null && File.Exists(item.FilePath()) ||
                    (transcoder.IsDirect && (object)stream != null) ||
                    (!transcoder.IsDirect && File.Exists(transcoder.OutputPath)))
                {
                    logger.IfInfo("Sending direct stream");
                    string mimeType = (object)transcoder == null ? item.FileType.MimeType() : transcoder.MimeType;
                    processor.Transcoder = transcoder;

                    if (uri.Parameters.ContainsKey("offsetSeconds"))
                    {
                        logger.IfInfo("Writing file at offsetSeconds " + uri.Parameters["offsetSeconds"]);
                    }

                    DateTime lastModified = transcoder.IsDirect ? DateTime.UtcNow : new FileInfo(transcoder.OutputPath).LastWriteTimeUtc;

                    // Direct write file
                    processor.WriteFile(stream, startOffset, length, mimeType, null, estimateContentLength, lastModified, limitToSize);
                    stream.Close();
                    logger.IfInfo("Successfully sent direct stream");

                    if (uri.Parameters.ContainsKey("offsetSeconds"))
                    {
                        logger.IfInfo("DONE writing file at offsetSeconds " + uri.Parameters["offsetSeconds"]);
                    }
                }
                else
                {
                    processor.WriteErrorHeader();
                }

                // Spin off a thread to consume the transcoder in 30 seconds.
                Thread consume = new Thread(() => transcodeService.ConsumedTranscode(transcoder));
                consume.Start();
            }
            catch (Exception e)
            {
                logger.Error(e);
            }
        }
Example #50
0
 /// <summary>
 /// Overload for IApiHandler interface
 /// </summary>
 public void Process(UriWrapper uri, IHttpProcessor processor, User user)
 {
     this.Process(uri, processor, user, "Invalid API call");
 }
Example #51
0
        private IList<int> ParseItemIds(UriWrapper uri)
        {
            // Try to get the itemIds
            IList<int> itemIds = new List<int>();
            if (uri.Parameters.ContainsKey("itemIds"))
            {
                string[] itemIdStrings = uri.Parameters["itemIds"].Split(',');

                foreach (string itemIdString in itemIdStrings)
                {
                    int itemId;
                    if (Int32.TryParse(itemIdString, out itemId))
                    {
                        itemIds.Add(itemId);
                    }
                }
            }

            return itemIds;
        }
Example #52
0
        /// <summary>
        /// Process performs a search for a query with specified types
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Lists to return as results
            IList <Artist>      artists      = new List <Artist>();
            IList <AlbumArtist> albumArtists = new List <AlbumArtist>();
            IList <Album>       albums       = new List <Album>();
            IList <Song>        songs        = new List <Song>();
            IList <Video>       videos       = new List <Video>();

            // If no query is provided, error
            if (!uri.Parameters.ContainsKey("query"))
            {
                processor.WriteJson(new SearchResponse("No search query provided", artists, albumArtists, albums, songs, videos));
                return;
            }

            // URL decode to strip any URL-encoded characters
            string query = HttpUtility.UrlDecode(uri.Parameters["query"]);

            // Ensure query is not blank
            if (query.Length < 1)
            {
                processor.WriteJson(new SearchResponse("Query cannot be empty", artists, albumArtists, albums, songs, videos));
                return;
            }

            // Check for query field
            string field = null;

            if (uri.Parameters.ContainsKey("field"))
            {
                // Use input field for query
                field = HttpUtility.UrlDecode(uri.Parameters["field"]);
            }

            // Check for exact match parameter
            bool exact = false;

            if (uri.Parameters.ContainsKey("exact") && uri.Parameters["exact"].IsTrue())
            {
                exact = true;
            }

            // If a query type is provided...
            if (uri.Parameters.ContainsKey("type"))
            {
                // Iterate all comma-separated values in query type
                foreach (string type in uri.Parameters["type"].Split(','))
                {
                    // Return results, populating lists depending on parameters specified
                    switch (type)
                    {
                    case "artists":
                        artists = Injection.Kernel.Get <IArtistRepository>().SearchArtists(field, query, exact);
                        break;

                    case "albumartists":
                        albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().SearchAlbumArtists(field, query, exact);
                        break;

                    case "albums":
                        albums = Injection.Kernel.Get <IAlbumRepository>().SearchAlbums(field, query, exact);
                        break;

                    case "songs":
                        songs = Injection.Kernel.Get <ISongRepository>().SearchSongs(field, query, exact);
                        break;

                    case "videos":
                        videos = Injection.Kernel.Get <IVideoRepository>().SearchVideos(field, query, exact);
                        break;

                    default:
                        artists = Injection.Kernel.Get <IArtistRepository>().SearchArtists(field, query, exact);
                        albums  = Injection.Kernel.Get <IAlbumRepository>().SearchAlbums(field, query, exact);
                        songs   = Injection.Kernel.Get <ISongRepository>().SearchSongs(field, query, exact);
                        videos  = Injection.Kernel.Get <IVideoRepository>().SearchVideos(field, query, exact);
                        break;
                    }
                }
            }
            else
            {
                // For no type, provide all types of data
                artists      = Injection.Kernel.Get <IArtistRepository>().SearchArtists(field, query, exact);
                albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().SearchAlbumArtists(field, query, exact);
                albums       = Injection.Kernel.Get <IAlbumRepository>().SearchAlbums(field, query, exact);
                songs        = Injection.Kernel.Get <ISongRepository>().SearchSongs(field, query, exact);
                videos       = Injection.Kernel.Get <IVideoRepository>().SearchVideos(field, query, exact);
            }

            // Check for a request to limit/paginate artists, like SQL
            // Note: can be combined with range or all artists
            if (uri.Parameters.ContainsKey("limit"))
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2)
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null, null, null));
                    return;
                }

                // Validate as integers
                int index    = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a valid integer start index", null, null, null, null, null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new SearchResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null, null, null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new SearchResponse("Parameter 'limit' requires a valid integer duration", null, null, null, null, null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new SearchResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null, null, null));
                        return;
                    }
                }

                // No duration?  Return just specified number of each item
                if (duration == Int32.MinValue)
                {
                    artists      = artists.Skip(0).Take(index).ToList();
                    albumArtists = albumArtists.Skip(0).Take(index).ToList();
                    albums       = albums.Skip(0).Take(index).ToList();
                    songs        = songs.Skip(0).Take(index).ToList();
                    videos       = videos.Skip(0).Take(index).ToList();
                }
                else
                {
                    // Else return items starting at index, and taking duration
                    artists      = artists.Skip(index).Take(duration).ToList();
                    albumArtists = albumArtists.Skip(index).Take(duration).ToList();
                    albums       = albums.Skip(index).Take(duration).ToList();
                    songs        = songs.Skip(index).Take(duration).ToList();
                    videos       = videos.Skip(index).Take(duration).ToList();
                }
            }

            // Return all results
            processor.WriteJson(new SearchResponse(null, artists, albumArtists, albums, songs, videos));
            return;
        }
Example #53
0
        /// <summary>
        /// Process is used to return a JSON object containing a variety of information about the host system
        /// which is running the WaveBox server
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            try {
                // Allocate an array of various statistics about the running process
                IDictionary <string, object> status = new Dictionary <string, object>();

                // Gather data about WaveBox process
                global::System.Diagnostics.Process proc = global::System.Diagnostics.Process.GetCurrentProcess();

                // Get current UNIX time
                long unixTime = DateTime.UtcNow.ToUnixTime();

                // Get current query log ID
                long queryLogId = Injection.Kernel.Get <IDatabase>().LastQueryLogId;

                // Get process ID
                status["pid"] = proc.Id;
                // Get uptime of WaveBox instance
                status["uptime"] = unixTime - WaveBoxService.StartTime.ToUnixTime();
                // Get last update time in UNIX format for status
                status["updated"] = unixTime;
                // Get hostname of machine
                status["hostname"] = System.Environment.MachineName;
                // Get WaveBox version
                status["version"] = WaveBoxService.BuildVersion;
                // Get build date
                status["buildDate"] = WaveBoxService.BuildDate.ToString("MMMM dd, yyyy");
                // Get host platform
                status["platform"] = WaveBoxService.OS.ToDescription();
                // Get current CPU usage
                status["cpuPercent"] = CpuUsage();
                // Get current memory usage in MB
                status["memoryMb"] = (float)proc.WorkingSet64 / 1024f / 1024f;
                // Get peak memory usage in MB
                status["peakMemoryMb"] = (float)proc.PeakWorkingSet64 / 1024f / 1024f;
                // Get list of media types WaveBox can index and serve (removing "Unknown")
                status["mediaTypes"] = Enum.GetNames(typeof(FileType)).Where(x => x != "Unknown").ToList();
                // Get list of transcoders available
                status["transcoders"] = Enum.GetNames(typeof(TranscodeType)).ToList();
                // Get list of services
                status["services"] = ServiceManager.GetServices();
                // Get last query log ID
                status["lastQueryLogId"] = queryLogId;

                // Call for extended status, which uses some database intensive calls
                if (uri.Parameters.ContainsKey("extended"))
                {
                    if (uri.Parameters["extended"].IsTrue())
                    {
                        // Check if any destructive queries have been performed since the last cache
                        if ((statusCache.LastQueryId == null) || (queryLogId > statusCache.LastQueryId))
                        {
                            // Update to the latest query log ID
                            statusCache.LastQueryId = queryLogId;

                            logger.IfInfo("Gathering extended status metrics from database");

                            // Get count of artists
                            statusCache.Cache["artistCount"] = Injection.Kernel.Get <IArtistRepository>().CountArtists();
                            // Get count of album artists
                            statusCache.Cache["albumArtistCount"] = Injection.Kernel.Get <IAlbumArtistRepository>().CountAlbumArtists();
                            // Get count of albums
                            statusCache.Cache["albumCount"] = Injection.Kernel.Get <IAlbumRepository>().CountAlbums();
                            // Get count of songs
                            statusCache.Cache["songCount"] = Injection.Kernel.Get <ISongRepository>().CountSongs();
                            // Get count of videos
                            statusCache.Cache["videoCount"] = Injection.Kernel.Get <IVideoRepository>().CountVideos();
                            // Get total file size of songs (bytes)
                            statusCache.Cache["songFileSize"] = Injection.Kernel.Get <ISongRepository>().TotalSongSize();
                            // Get total file size of videos (bytes)
                            statusCache.Cache["videoFileSize"] = Injection.Kernel.Get <IVideoRepository>().TotalVideoSize();
                            // Get total song duration
                            statusCache.Cache["songDuration"] = Injection.Kernel.Get <ISongRepository>().TotalSongDuration();
                            // Get total video duration
                            statusCache.Cache["videoDuration"] = Injection.Kernel.Get <IVideoRepository>().TotalVideoDuration();

                            logger.IfInfo("Metric gathering complete, cached results!");
                        }

                        // Append cached status dictionary to status
                        status = status.Concat(statusCache.Cache).ToDictionary(x => x.Key, x => x.Value);
                    }
                }

                // Return all status
                processor.WriteJson(new StatusResponse(null, status));
                return;
            } catch (Exception e) {
                logger.Error(e);
            }

            // Return error
            processor.WriteJson(new StatusResponse("Could not retrieve server status", null));
            return;
        }
        // Process API calls based on the class's HTTP URL
        private void ApiProcess()
        {
            // The API request wrapper
            UriWrapper uri = new UriWrapper(this.HttpUrl, this.HttpMethod);

            // The user who is accessing the API
            User apiUser = null;

            // The handler being accessed
            IApiHandler api = null;

            // No API request found?  Serve web UI
            if (!uri.IsApiCall)
            {
                api = Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("web");
                api.Process(uri, this, apiUser);
                return;
            }

            // Get client IP address
            string ip = ((IPEndPoint)this.Socket.Client.RemoteEndPoint).Address.ToString();

            // Check for valid API action ("web" and "error" are technically valid, but can't be used in this way)
            if (uri.ApiAction == null || uri.ApiAction == "web" || uri.ApiAction == "error")
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Invalid API call");
                logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                return;
            }

            // Check for session cookie authentication, unless this is a login request
            string sessionId = null;

            if (uri.ApiAction != "login")
            {
                sessionId = this.GetSessionCookie();
                apiUser   = Injection.Kernel.Get <IApiAuthenticate>().AuthenticateSession(sessionId);
            }

            // If no cookie, try parameter authentication
            if (apiUser == null)
            {
                apiUser = Injection.Kernel.Get <IApiAuthenticate>().AuthenticateUri(uri);

                // If user still null, failed authentication, so serve error
                if (apiUser == null)
                {
                    ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                    errorApi.Process(uri, this, apiUser, "Authentication failed");
                    logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                    return;
                }
            }

            // apiUser.SessionId will be generated on new login, so that takes precedence for new session cookie
            apiUser.SessionId = apiUser.SessionId ?? sessionId;
            this.SetSessionCookie(apiUser.SessionId);

            // Store user's current session object
            apiUser.CurrentSession = Injection.Kernel.Get <ISessionRepository>().SessionForSessionId(apiUser.SessionId);

            // Retrieve the requested API handler by its action
            IApiHandler apiHandler = Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler(uri.ApiAction);

            // Check for valid API action
            if (apiHandler == null)
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Invalid API call");
                logger.IfInfo(String.Format("[{0}] API: {1}", ip, this.HttpUrl));
                return;
            }

            // Log API call
            logger.IfInfo(String.Format("[{0}/{1}@{2}] API: {3} {4}", apiUser.UserName, apiUser.CurrentSession.ClientName, ip, this.HttpMethod, this.HttpUrl));

            // Check if user has appropriate permissions for this action on this API handler
            if (!apiHandler.CheckPermission(apiUser, uri.Action))
            {
                ErrorApiHandler errorApi = (ErrorApiHandler)Injection.Kernel.Get <IApiHandlerFactory>().CreateApiHandler("error");
                errorApi.Process(uri, this, apiUser, "Permission denied");
                return;
            }

            // Finally, process and return results
            apiHandler.Process(uri, this, apiUser);
        }
Example #55
0
        /// <summary>
        /// Process returns a list of videos from WaveBox
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Return list of videos
            IList <Video> videos = new List <Video>();

            // Check if ID present
            if (uri.Id != null)
            {
                // Add video by ID to the list
                videos.Add(Injection.Kernel.Get <IVideoRepository>().VideoForId((int)uri.Id));
            }
            // Check for a request for range of videos
            else if (uri.Parameters.ContainsKey("range"))
            {
                string[] range = uri.Parameters["range"].Split(',');

                // Ensure valid range was parsed
                if (range.Length != 2)
                {
                    processor.WriteJson(new VideosResponse("Parameter 'range' requires a valid, comma-separated character tuple", null));
                    return;
                }

                // Validate as characters
                char start, end;
                if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end))
                {
                    processor.WriteJson(new VideosResponse("Parameter 'range' requires characters which are single alphanumeric values", null));
                    return;
                }

                // Grab range of videos
                videos = Injection.Kernel.Get <IVideoRepository>().RangeVideos(start, end);
            }

            // Check for a request to limit/paginate videos, like SQL
            // Note: can be combined with range or all videos
            if (uri.Parameters.ContainsKey("limit") && uri.Id == null)
            {
                string[] limit = uri.Parameters["limit"].Split(',');

                // Ensure valid limit was parsed
                if (limit.Length < 1 || limit.Length > 2)
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null));
                    return;
                }

                // Validate as integers
                int index    = 0;
                int duration = Int32.MinValue;
                if (!Int32.TryParse(limit[0], out index))
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a valid integer start index", null));
                    return;
                }

                // Ensure positive index
                if (index < 0)
                {
                    processor.WriteJson(new VideosResponse("Parameter 'limit' requires a non-negative integer start index", null));
                    return;
                }

                // Check for duration
                if (limit.Length == 2)
                {
                    if (!Int32.TryParse(limit[1], out duration))
                    {
                        processor.WriteJson(new VideosResponse("Parameter 'limit' requires a valid integer duration", null));
                        return;
                    }

                    // Ensure positive duration
                    if (duration < 0)
                    {
                        processor.WriteJson(new VideosResponse("Parameter 'limit' requires a non-negative integer duration", null));
                        return;
                    }
                }

                // Check if results list already populated by range
                if (videos.Count > 0)
                {
                    // No duration?  Return just specified number of videos
                    if (duration == Int32.MinValue)
                    {
                        videos = videos.Skip(0).Take(index).ToList();
                    }
                    else
                    {
                        // Else, return videos starting at index, up to count duration
                        videos = videos.Skip(index).Take(duration).ToList();
                    }
                }
                else
                {
                    // If no videos in list, grab directly using model method
                    videos = Injection.Kernel.Get <IVideoRepository>().LimitVideos(index, duration);
                }
            }

            // Finally, if no videos already in list, send the whole list
            if (videos.Count == 0)
            {
                videos = Injection.Kernel.Get <IVideoRepository>().AllVideos();
            }

            // Send it!
            processor.WriteJson(new VideosResponse(null, videos));
            return;
        }