상속: IGroupingItem
예제 #1
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);
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="WaveBox.ApiHandler.Handlers.Lastfm"/> class.
        /// </summary>
        /// <param name='userId'>
        /// User identifier.
        /// </param>
        public Lastfm(User theUser)
        {
            user = theUser;
            sessionKey = user.LastfmSession;

            // If the session key is prepended by 'token:', then the user has already generated a request token.
            // we should now try to get a session using that token.  If this fails, that simply means the user
            // has not granted us access yet.  If there is no session key at all, then we should request a token
            // and do nothing else.

            if (sessionKey == null)
            {
                this.CreateAuthUrl();
                logger.IfInfo(this.AuthUrl);
            }
            else if (sessionKey.Substring(0, 6) == "token:")
            {
                string token = sessionKey.Substring(6);
                this.GetSessionKeyAndUpdateUser(token);
            }
            else
            {
                sessionAuthenticated = true;
            }
        }
예제 #3
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();
            }
        }
예제 #5
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;
        }
예제 #6
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;
        }
예제 #7
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);
            }
        }
예제 #8
0
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Read out settings
            if (uri.Action == "read" || uri.Action == null)
            {
                // If no parameter provided, return settings
                processor.WriteJson(new SettingsResponse(null, Injection.Kernel.Get<IServerSettings>().SettingsModel));
                return;
            }

            // Check for required JSON parameter
            if (!uri.Parameters.ContainsKey("json"))
            {
                processor.WriteJson(new SettingsResponse("Missing required parameter 'json'", null));
                return;
            }

            // Update settings
            if (uri.Action == "update")
            {
                // Take in settings in the JSON format (same as it is stored on disk),
                // pass it on to the Settings class for processing
                string json = HttpUtility.UrlDecode(uri.Parameters["json"]);

                // Attempt to write settings
                bool success = false;
                try
                {
                    success = Injection.Kernel.Get<IServerSettings>().WriteSettings(json);
                    Injection.Kernel.Get<IServerSettings>().Reload();
                }
                catch (JsonException)
                {
                    // Failure if invalid JSON provided
                    processor.WriteJson(new SettingsResponse("Invalid JSON", null));
                    return;
                }

                // If settings fail to write, report error
                if (!success)
                {
                    processor.WriteJson(new SettingsResponse("Settings could not be changed", null));
                    return;
                }

                // If settings wrote successfully, return success
                processor.WriteJson(new SettingsResponse(null, Injection.Kernel.Get<IServerSettings>().SettingsModel));
                return;
            }

            // Invalid action
            processor.WriteJson(new SettingsResponse("Invalid action", null));
            return;
        }
예제 #9
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;
        }
예제 #10
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;
        }
예제 #11
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;
        }
예제 #12
0
 // Standard permissions
 public bool CheckPermission(User user, string action)
 {
     switch (action)
     {
         // Write
         case "update":
             return user.HasPermission(Role.User);
         // Read
         case "read":
         default:
             return user.HasPermission(Role.Test);
     }
 }
예제 #13
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;
        }
예제 #14
0
 // Standard permissions
 public bool CheckPermission(User user, string action)
 {
     switch (action)
     {
         // Write
         case "add":
         case "create":
         case "delete":
         case "insert":
         case "move":
         case "remove":
             return user.HasPermission(Role.User);
         // Read
         case "read":
         default:
             return user.HasPermission(Role.Test);
     }
 }
예제 #15
0
 // Standard permissions
 public bool CheckPermission(User user, string action)
 {
     switch (action)
     {
         // Admin
         case "create":
         case "delete":
         case "killSession":
             return user.HasPermission(Role.Admin);
         // Write
         // update - so user can update their own username/password, but not role
         case "update":
             return user.HasPermission(Role.User);
         // Read
         case "read":
         default:
             return user.HasPermission(Role.Test);
     }
 }
예제 #16
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();
        }
예제 #17
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);
            }
        }
예제 #18
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;
        }
예제 #19
0
 // API handler is read-only, so no permissions checks needed
 public bool CheckPermission(User user, string action)
 {
     return true;
 }
예제 #20
0
 // Only standard user and up may report stats
 public bool CheckPermission(User user, string action)
 {
     return user.HasPermission(Role.User);
 }
예제 #21
0
파일: User.cs 프로젝트: einsteinx2/WaveBox
 public static int CompareUsersByName(User x, User y)
 {
     return StringComparer.OrdinalIgnoreCase.Compare(x.UserName, y.UserName);
 }
예제 #22
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);
            }
        }
예제 #23
0
 /// <summary>
 /// Overload for IApiHandler interface
 /// </summary>
 public void Process(UriWrapper uri, IHttpProcessor processor, User user)
 {
     this.Process(uri, processor, user, "Invalid API call");
 }
예제 #24
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;
        }
예제 #25
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;
        }
예제 #26
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;
        }
예제 #27
0
        /// <summary>
        /// Process records play stats for artists, albums, songs
        /// </summary>
        public void Process(UriWrapper uri, IHttpProcessor processor, User user)
        {
            // Ensure an event is present
            if (!uri.Parameters.ContainsKey("event"))
            {
                processor.WriteJson(new StatsResponse("Please specify an event parameter with comma separated list of events"));
                return;
            }

            // Split events into id, stat type, UNIX timestamp triples
            string[] events = uri.Parameters["event"].Split(',');

            // Ensure data sent
            if (events.Length < 1)
            {
                // Report empty data list
                processor.WriteJson(new StatsResponse("Event data list is empty"));
                return;
            }

            // Ensure events are in triples
            if (events.Length % 3 != 0)
            {
                processor.WriteJson(new StatsResponse("Event data list must be in comma-separated triples of form itemId,statType,timestamp"));
                return;
            }

            // Iterate all events
            for (int i = 0; i <= events.Length - 3; i += 3)
            {
                // Store item ID, stat type, and UNIX timestamp
                string itemId = events[i];
                string statType = events[i+1];
                string timeStamp = events[i+2];

                // Initialize to null defaults
                int itemIdInt = -1;
                StatType statTypeEnum = StatType.Unknown;
                long timeStampLong = -1;

                // Perform three checks for valid item ID, stat type, UNIX timestamp
                bool success = Int32.TryParse(itemId, out itemIdInt);
                if (success)
                {
                    success = Enum.TryParse<StatType>(statType, true, out statTypeEnum);
                }
                if (success)
                {
                    success = Int64.TryParse(timeStamp, out timeStampLong);
                }
                if (success)
                {
                    // If all three are successful, generate an item type from the ID
                    ItemType itemType = Injection.Kernel.Get<IItemRepository>().ItemTypeForItemId(itemIdInt);

                    // Case: type is song, stat is playcount
                    if ((itemType == ItemType.Song) && (statTypeEnum == StatType.PLAYED))
                    {
                        // Also record a play for the artist, album, and folder
                        Song song = Injection.Kernel.Get<ISongRepository>().SongForId(itemIdInt);

                        // Trigger now playing service if available
                        NowPlayingService nowPlaying = (NowPlayingService)ServiceManager.GetInstance("nowplaying");
                        if (nowPlaying != null)
                        {
                            nowPlaying.Register(user, song, timeStampLong);
                        }

                        if ((object)song.AlbumId != null)
                        {
                            Injection.Kernel.Get<IStatRepository>().RecordStat((int)song.AlbumId, statTypeEnum, timeStampLong);
                        }
                        if ((object)song.ArtistId != null)
                        {
                            Injection.Kernel.Get<IStatRepository>().RecordStat((int)song.ArtistId, statTypeEnum, timeStampLong);
                        }
                        if ((object)song.FolderId != null)
                        {
                            Injection.Kernel.Get<IStatRepository>().RecordStat((int)song.FolderId, statTypeEnum, timeStampLong);
                        }
                    }

                    // Record stats for the generic item
                    Injection.Kernel.Get<IStatRepository>().RecordStat(itemIdInt, statTypeEnum, timeStampLong);
                }
            }

            // After all stat iterations, return a successful response
            processor.WriteJson(new StatsResponse(null));
        }
예제 #28
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;
        }
예제 #29
0
        public bool Register(User user, IMediaItem m, long? timestamp = null)
        {
            // Begin building object
            NowPlaying nowPlaying = new NowPlaying();

            // Store user object
            nowPlaying.User = user;

            // Check if client sent a timestamp (if not, use current time)
            if (timestamp == null)
            {
                timestamp = DateTime.UtcNow.ToUnixTime();
            }

            // Capture play time to set up automatic unregister on playback end
            nowPlaying.StartTime = timestamp;
            nowPlaying.EndTime = timestamp + Convert.ToInt32(m.Duration);

            // Start a timer, set to elapse and unregister this song exactly when it should finish playback
            nowPlaying.Timer = new Timer(Convert.ToInt32(m.Duration) * 1000);
            nowPlaying.Timer.Elapsed += delegate { this.Unregister(user.UserName, user.CurrentSession.ClientName); };
            nowPlaying.Timer.Start();

            // Capture media item's type
            Type mediaType = m.GetType();

            // Unregister any items with matching user and client
            this.Unregister(user.UserName, user.CurrentSession.ClientName);

            // Handling for Song items
            if (mediaType.IsAssignableFrom(typeof(Song)))
            {
                // Box IMediaItem to Song
                Song s = (Song)m;
                nowPlaying.MediaItem = s;

                // Report now playing
                playing.Add(nowPlaying);
                logger.IfInfo(String.Format("{0}@{1} Now Playing: {2} - {3} - {4} [{5}]",
                    user.UserName,
                    user.CurrentSession.ClientName,
                    s.ArtistName,
                    s.AlbumName,
                    s.SongName,
                    Convert.ToInt32(s.Duration).ToTimeString()
                ));
            }
            // Handling for Video items
            else if (mediaType.IsAssignableFrom(typeof(Video)))
            {
                // Box IMediaItem to Video
                Video v = (Video)m;
                nowPlaying.MediaItem = v;

                // Report now playing
                playing.Add(nowPlaying);
                logger.IfInfo(String.Format("{0}@{1} Now Watching: {2} [{3}]",
                    user.UserName,
                    user.CurrentSession.ClientName,
                    v.FileName,
                    Convert.ToInt32(v.Duration).ToTimeString()
                ));
            }
            else
            {
                // Report unsupported media types
                logger.IfInfo("Media type not supported, skipping now playing registration...");
            }

            return true;
        }
예제 #30
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));
        }