/// <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; } }
public void startQueue() { queueThread = new Thread(delegate() { while (queueShouldLoop) { lock (operationQueue) { if (operationQueue.Count > 0 && operationQueue.Peek() != null && operationQueue.Peek().IsReady) { try { currentOperation = operationQueue.Dequeue(); } catch { currentOperation = null; } if (currentOperation != null) { currentOperation.Run(); logger.IfInfo(currentOperation.ToString() + " fired"); } } } // Sleep to prevent a tight loop Thread.Sleep(DEFAULT_PRECISION); } }); queueThread.IsBackground = true; queueThread.Start(); }
/// <summary> /// Process performs a HLS transcode on a media item /// </summary> public void Process(UriWrapper uri, IHttpProcessor processor, User user) { // Verify ID received if (uri.Id == null) { processor.WriteJson(new TranscodeHlsResponse("Missing required parameter 'id'")); return; } try { // Get the media item associated with this id ItemType itemType = Injection.Kernel.Get <IItemRepository>().ItemTypeForItemId((int)uri.Id); IMediaItem item = null; if (itemType == ItemType.Song) { item = Injection.Kernel.Get <ISongRepository>().SongForId((int)uri.Id); logger.IfInfo("HLS transcoding for songs not currently supported"); // CURRENTLY DO NOT SUPPORT HLS STREAMING FOR SONGS return; } else if (itemType == ItemType.Video) { item = Injection.Kernel.Get <IVideoRepository>().VideoForId((int)uri.Id); logger.IfInfo("Preparing video stream: " + item.FileName); } // Return an error if none exists if ((item == null) || (!File.Exists(item.FilePath()))) { processor.WriteJson(new TranscodeHlsResponse("No media item exists with ID: " + (int)uri.Id)); return; } // Generate the playlist file string response = null; string[] transQualities = uri.Parameters.ContainsKey("transQuality") ? uri.Parameters["transQuality"].Split(',') : new string[] { "Medium" }; if (transQualities.Length == 1) { // This is a single playlist response = this.GeneratePlaylist(item, transQualities[0], uri); } else { // This is a multi playlist response = this.GenerateMultiPlaylist(item, transQualities, uri); } processor.WriteText(response, "application/x-mpegURL"); logger.IfInfo("Successfully HLS transcoded file!"); } catch (Exception e) { logger.Error(e); } }
public void DatabaseSetup() { if (!File.Exists(DatabasePath)) { try { logger.IfInfo("Database file doesn't exist; Creating it : " + DATABASE_FILE_NAME); // new filestream on the template FileStream dbTemplate = new FileStream(DatabaseTemplatePath, FileMode.Open); // a new byte array byte[] dbData = new byte[dbTemplate.Length]; // read the template file into memory dbTemplate.Read(dbData, 0, Convert.ToInt32(dbTemplate.Length)); // write it all out System.IO.File.WriteAllBytes(DatabasePath, dbData); // close the template file dbTemplate.Close(); } catch (Exception e) { logger.Error(e); } } if (!File.Exists(QuerylogPath)) { try { logger.IfInfo("Query log database file doesn't exist; Creating it : " + QUERY_LOG_FILE_NAME); // new filestream on the template FileStream dbTemplate = new FileStream(QuerylogTemplatePath, FileMode.Open); // a new byte array byte[] dbData = new byte[dbTemplate.Length]; // read the template file into memory dbTemplate.Read(dbData, 0, Convert.ToInt32(dbTemplate.Length)); // write it all out System.IO.File.WriteAllBytes(QuerylogPath, dbData); // close the template file dbTemplate.Close(); } catch (Exception e) { logger.Error(e); } } }
public void WriteSuccessHeader(long contentLength, string mimeType, IDictionary <string, string> customHeaders, DateTime lastModified, bool isPartial = false, string encoding = null) { StreamWriter outStream = new StreamWriter(new BufferedStream(this.Socket.GetStream())); string status = isPartial ? "HTTP/1.1 206 Partial Content" : "HTTP/1.1 200 OK"; outStream.WriteLine(status); outStream.WriteLine("Date: " + DateTime.UtcNow.ToRFC1123()); outStream.WriteLine("Server: WaveBox/" + WaveBoxService.BuildVersion); outStream.WriteLine("Last-Modified: " + lastModified.ToRFC1123()); outStream.WriteLine("ETag: \"" + lastModified.ToETag() + "\""); outStream.WriteLine("Accept-Ranges: bytes"); // Check request for compression if (encoding != null) { outStream.WriteLine("Content-Encoding: " + encoding); } if (contentLength >= 0) { outStream.WriteLine("Content-Length: " + contentLength); } outStream.WriteLine("Access-Control-Allow-Origin: *"); outStream.WriteLine("Content-Type: " + mimeType); if ((object)customHeaders != null) { foreach (string key in customHeaders.Keys) { outStream.WriteLine(key + ": " + customHeaders[key]); } } // Inject delayed headers foreach (string key in this.DelayedHeaders.Keys) { outStream.WriteLine(key + ": " + DelayedHeaders[key]); } outStream.WriteLine("Connection: close"); outStream.WriteLine(""); outStream.Flush(); // Only log API responses if (HttpUrl.Contains("api")) { logger.IfInfo(String.Format("{0}, Length: {1}, Encoding: {2}, ETag: {3}, Last-Modified: {4}", status, contentLength, encoding ?? "none", lastModified.ToETag(), lastModified.ToRFC1123() )); } }
public ITranscoder TranscodeSong(IMediaItem song, TranscodeType type, uint quality, bool isDirect, uint offsetSeconds, uint lengthSeconds) { if (!this.Running) { logger.Error("TranscodeService is not running!"); return(null); } logger.IfInfo("Asked to transcode song: " + song.FileName); lock (transcoders) { ITranscoder transcoder = null; switch (type) { case TranscodeType.MP3: transcoder = new FFMpegMP3Transcoder(song, quality, isDirect, offsetSeconds, lengthSeconds); break; case TranscodeType.OGG: transcoder = new FFMpegOGGTranscoder(song, quality, isDirect, offsetSeconds, lengthSeconds); break; case TranscodeType.OPUS: transcoder = new FFMpegOpusTranscoder(song, quality, isDirect, offsetSeconds, lengthSeconds); break; case TranscodeType.AAC: transcoder = new FFMpegAACTranscoder(song, quality, isDirect, offsetSeconds, lengthSeconds); break; } transcoder = StartTranscoder(transcoder); return(transcoder); } }
public bool Start() { // FOR NOW: Use the pre-existing delayed operation queues. Once more work has been done, cron will // run a unified timer and spin each of these off as needed logger.IfInfo("Scheduling and starting all cronjobs..."); // Start user and session purge operation UserPurge.Queue.queueOperation(new UserPurgeOperation(0)); UserPurge.Queue.startQueue(); logger.IfInfo("All cronjobs started!"); return(true); }
/// <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> /// The main instance of WaveBox which runs the server. Creates necessary directories, initializes /// database and settings, and starts all associated services. /// </summary> public void Start() { logger.IfInfo("Initializing WaveBox " + WaveBoxService.BuildVersion + " on " + WaveBoxService.OS.ToDescription() + " platform..."); // Initialize ImageMagick try { ImageMagickInterop.WandGenesis(); } catch (Exception e) { logger.Error("Error loading ImageMagick DLL:", e); } // Create directory for WaveBox's root path, if it doesn't exist string rootDir = ServerUtility.RootPath(); if (!Directory.Exists(rootDir)) { Directory.CreateDirectory(rootDir); } // Create directory for WaveBox Web UI themes, if it doesn't exist string themeDir = ServerUtility.ExecutablePath() + "themes/"; if (!Directory.Exists(themeDir)) { Directory.CreateDirectory(themeDir); } // Perform initial setup of Settings, Database Injection.Kernel.Get <IDatabase>().DatabaseSetup(); Injection.Kernel.Get <IServerSettings>().SettingsSetup(); // Start services try { // Initialize factory, so it can register all services for deployment ServiceFactory.Initialize(); // Start user defined services if (Injection.Kernel.Get <IServerSettings>().Services != null) { ServiceManager.AddList(Injection.Kernel.Get <IServerSettings>().Services); } else { logger.Warn("No services specified in configuration file!"); } ServiceManager.StartAll(); } catch (Exception e) { logger.Warn("Could not start one or more WaveBox services, please check services in your configuration"); logger.Warn(e); } // Temporary: create test and admin user Injection.Kernel.Get <IUserRepository>().CreateUser("test", "test", Role.User, null); Injection.Kernel.Get <IUserRepository>().CreateUser("admin", "admin", Role.Admin, null); return; }
private void DeviceFound(object sender, DeviceEventArgs args) { logger.IfInfo("Device Found"); this.Status = NatStatus.DeviceFound; // This is the upnp enabled router this.Device = args.Device; // Create a mapping to forward external port to local port try { Device.CreatePortMap(new Mapping(Protocol.Tcp, Injection.Kernel.Get <IServerSettings>().Port, Injection.Kernel.Get <IServerSettings>().Port)); this.Status = NatStatus.PortForwardedSuccessfully; } catch (Exception e) { this.Status = NatStatus.PortForwardingFailed; logger.Error("Port mapping failed", e); } }
public void ExtendWaitOrRestart() { if (state == DelayedOperationState.Queued) { ResetWait(); logger.IfInfo("Extending wait period."); } else if (state == DelayedOperationState.Running) { Restart(); } }
/// <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; }
/// <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; }
/// <summary> /// Start user purge operation /// </summary> public static void Start() { // Delete all expired users foreach (User u in Injection.Kernel.Get <IUserRepository>().ExpiredUsers()) { if (u.Delete()) { logger.IfInfo(String.Format("Purged expired user: [id: {0}, name: {1}]", u.UserId, u.UserName)); } else { logger.IfInfo(String.Format("Failed to purge expired user: [id: {0}, name: {1}]", u.UserId, u.UserName)); } } // Grab a list of all sessions var sessions = Injection.Kernel.Get <ISessionRepository>().AllSessions(); // Grab the current UNIX time long unixTime = DateTime.UtcNow.ToUnixTime(); // Purge any sessions which have not been updated in a predefined period of time foreach (Session s in sessions) { // Check current time and last update, purge if the diff is higher than SessionTimeout minutes if ((unixTime - Convert.ToInt32(s.UpdateTime)) >= (Injection.Kernel.Get <IServerSettings>().SessionTimeout * 60)) { if (s.Delete()) { logger.IfInfo(String.Format("Purged session: [id: {0}, user: {1}]", s.RowId, s.UserId)); } else { logger.IfInfo(String.Format("Failed to purge session: [id: {0}, user: {1}]", s.RowId, s.UserId)); } } } }
public override void Start() { logger.IfInfo("------------- ARTIST ART SCAN -------------"); Stopwatch testTotalScanTime = new Stopwatch(); testTotalScanTime.Start(); // Create the cache directory if it doesn't exist yet if (!Directory.Exists(cachePath)) { Directory.CreateDirectory(cachePath); } // Keep a set of all MusicBrainz IDs known to WaveBox ISet <string> musicBrainzIds = new HashSet <string>(); // Find artists and album artists missing art IArtistRepository artistRepository = Injection.Kernel.Get <IArtistRepository>(); IList <Artist> allArtists = artistRepository.AllArtists(); foreach (Artist artist in allArtists) { string musicBrainzId = artist.MusicBrainzId; if (musicBrainzId != null) { if (!File.Exists(this.ArtPathForMusicBrainzId(musicBrainzId))) { musicBrainzIds.Add(musicBrainzId); } } } IAlbumArtistRepository albumArtistRepository = Injection.Kernel.Get <IAlbumArtistRepository>(); IList <AlbumArtist> allAlbumArtists = albumArtistRepository.AllAlbumArtists(); foreach (AlbumArtist albumArtist in allAlbumArtists) { string musicBrainzId = albumArtist.MusicBrainzId; if (musicBrainzId != null) { if (!File.Exists(this.ArtPathForMusicBrainzId(musicBrainzId))) { musicBrainzIds.Add(musicBrainzId); } } } // Scan all MusicBrainz IDs collected by WaveBox int downloadCount = this.ScanIds(musicBrainzIds); testTotalScanTime.Stop(); logger.IfInfo("------------- ARTIST ART SCAN -------------"); logger.IfInfo("items retrieved: " + downloadCount); logger.IfInfo("total scan time: " + testTotalScanTime.ElapsedMilliseconds + "ms"); logger.IfInfo("-------------------------------------------"); }
/// <summary> /// Use reflection to scan for all available IService-implementing classes, register them as valid services /// to be created by factory /// <summary> public static void Initialize() { try { // Grab all available types which implement IService foreach (Type t in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IService)))) { // Discover and instantiate all available services IService instance = (IService)Activator.CreateInstance(t); logger.IfInfo("Discovered service: " + instance.Name + " -> " + t); services.Add(instance); } } catch (Exception e) { logger.Error(e); } }
public void CancelTranscode() { if (TranscodeProcess != null) { logger.IfInfo("Cancelling transcode for " + Item.FileName); // Kill the process TranscodeProcess.Kill(); TranscodeProcess = null; // Wait for the thread to die TranscodeThread.Join(); TranscodeThread = null; // Set the state State = TranscodeState.Canceled; // Inform the delegate if ((object)TranscoderDelegate != null) { TranscoderDelegate.TranscodeFailed(this); } } }
/// <summary> /// Use reflection to scan for all available IApiHandler-implementing classes, register them as valid API /// handlers to be created by factory /// <summary> public void Initialize() { try { // Initialize list apiHandlers = new List <IApiHandler>(); // Grab all available types which implement IApiHandler foreach (Type t in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IApiHandler)))) { // Discover and instantiate all available apiHandlers IApiHandler instance = (IApiHandler)Activator.CreateInstance(t); logger.IfInfo("Discovered API: " + instance.Name + " -> " + t); this.apiHandlers.Add(instance); } } catch (Exception e) { logger.Error(e); } }
public void RemoveMediaItemAtIndexes(IList <int> indices) { ISQLiteConnection conn = null; try { conn = Injection.Kernel.Get <IDatabase>().GetSqliteConnection(); conn.BeginTransaction(); // delete the items at the indicated indices foreach (int index in indices) { logger.IfInfo("Deleting row at ItemPosition: " + index); conn.ExecuteLogged("DELETE FROM PlaylistItem WHERE PlaylistId = ? AND ItemPosition = ?", PlaylistId, index); } // select the id of all members of the playlist var result = conn.Query <PlaylistItem>("SELECT * FROM PlaylistItem WHERE PlaylistId = ? ORDER BY ItemPosition", PlaylistId); // update the values of each index in the array to be the new index for (int i = 0; i < result.Count; i++) { var item = result[i]; conn.ExecuteLogged("UPDATE PlaylistItem SET ItemPosition = ? WHERE PlaylistItemId = ? AND PlaylistId = ?", i, item.PlaylistItemId, PlaylistId); } conn.Commit(); } catch (Exception e) { if (!ReferenceEquals(conn, null)) { conn.Rollback(); } logger.Error(e); } finally { Injection.Kernel.Get <IDatabase>().CloseSqliteConnection(conn); } }
public int?GetParentFolderId(string path) { string parentFolderPath = Directory.GetParent(path).FullName; int?pFolderId = null; int id = this.database.GetScalar <int>("SELECT FolderId FROM Folder WHERE FolderPath = ?", parentFolderPath); if (id == 0) { logger.IfInfo("No db result for parent folder. Constructing parent folder object."); Folder f = FolderForPath(parentFolderPath); f.InsertFolder(false); pFolderId = f.FolderId; } else { pFolderId = id; } return(pFolderId); }
/// <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); } }
private byte[] ResizeImageMagick(Stream stream, int width, double blurSigma) { // new wand IntPtr wand = ImageMagickInterop.NewWand(); // get original image byte[] b = new byte[stream.Length]; stream.Read(b, 0, (int)stream.Length); bool success = ImageMagickInterop.ReadImageBlob(wand, b); if (success) { int sourceWidth = (int)ImageMagickInterop.GetWidth(wand); int sourceHeight = (int)ImageMagickInterop.GetHeight(wand); float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)width / (float)sourceWidth); nPercentH = ((float)width / (float)sourceHeight); if (nPercentH < nPercentW) { nPercent = nPercentH; } else { nPercent = nPercentW; } int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); Stopwatch s = new Stopwatch(); s.Start(); ImageMagickInterop.ResizeImage(wand, (IntPtr)destWidth, (IntPtr)destHeight, ImageMagickInterop.Filter.Lanczos, 1.0); s.Stop(); logger.IfInfo("resize image time: " + s.ElapsedMilliseconds + "ms"); Stopwatch s1 = new Stopwatch(); if (blurSigma > 0.0) { s1.Start(); ImageMagickInterop.BlurImage(wand, 0.0, blurSigma); s1.Stop(); logger.IfInfo("blur image time: " + s1.ElapsedMilliseconds + "ms"); } logger.IfInfo("total image time: " + (s.ElapsedMilliseconds + s1.ElapsedMilliseconds) + "ms"); byte[] newData = ImageMagickInterop.GetImageBlob(wand); // cleanup ImageMagickInterop.DestroyWand(wand); return(newData); } else { return(b); } }
public override void Start() { Stopwatch sw = new Stopwatch(); logger.IfInfo("---------------- ORPHAN SCAN ----------------"); logger.IfInfo("Folders:"); sw.Start(); this.CheckFolders(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("Songs:"); sw.Restart(); this.CheckSongs(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("Artists:"); sw.Restart(); this.CheckArtists(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("AlbumArtists:"); sw.Restart(); this.CheckAlbumArtists(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("Albums:"); sw.Restart(); this.CheckAlbums(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("Genres:"); sw.Restart(); this.CheckGenres(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("Videos:"); sw.Restart(); this.CheckVideos(); sw.Stop(); logger.IfInfo("Done, elapsed: " + sw.ElapsedMilliseconds + "ms"); logger.IfInfo("DONE, TOTAL ELAPSED: " + (totalExistsTime / 10000) + "ms"); logger.IfInfo("---------------------------------------------"); }
/// <summary> /// Process a Last.fm API request /// </summary> public void Process(UriWrapper uri, IHttpProcessor processor, User user) { // Create Last.fm object for this user Lastfm lfm = new Lastfm(user); // Pull URL parameters for Last.fm integration string eve = null; uri.Parameters.TryGetValue("event", out eve); if (uri.Action == null || uri.Action == "auth") { // If not authenticated, pass back authorization URL if (!lfm.SessionAuthenticated) { processor.WriteJson(new ScrobbleResponse(null, lfm.AuthUrl)); } else { // Else, already authenticated processor.WriteJson(new ScrobbleResponse("LFMAlreadyAuthenticated")); } return; } // If Last.fm is not authenticated, provide an authorization URL if (!lfm.SessionAuthenticated) { logger.IfInfo("You must authenticate before you can scrobble."); processor.WriteJson(new ScrobbleResponse("LFMNotAuthenticated", lfm.AuthUrl)); return; } // Create list of scrobble data IList <LfmScrobbleData> scrobbles = new List <LfmScrobbleData>(); // Get Last.fm API enumerations LfmScrobbleType scrobbleType = Lastfm.ScrobbleTypeForString(uri.Action); // On invalid scrobble type, return error JSON if (scrobbleType == LfmScrobbleType.INVALID) { processor.WriteJson(new ScrobbleResponse("LFMInvalidScrobbleType")); return; } // On now playing scrobble type if (scrobbleType == LfmScrobbleType.NOWPLAYING) { // Ensure ID specified for scrobble if (uri.Id == null) { processor.WriteJson(new ScrobbleResponse("LFMNoIdSpecifiedForNowPlaying")); return; } // Add successful scrobble to list, submit scrobbles.Add(new LfmScrobbleData((int)uri.Id, null)); lfm.Scrobble(scrobbles, scrobbleType); } // Else, unknown scrobble event else { // On null event, return error JSON if (eve == null) { processor.WriteJson(new ScrobbleResponse("LFMNoEventSpecifiedForScrobble")); return; } // Ensure input is a comma-separated pair string[] input = eve.Split(','); if ((input.Length % 2) != 0) { processor.WriteJson(new ScrobbleResponse("LFMInvalidInput")); return; } // Add scrobbles from input data pairs int i = 0; while (i < input.Length) { scrobbles.Add(new LfmScrobbleData(int.Parse(input[i]), long.Parse(input[i + 1]))); i = i + 2; } } // Scrobble all plays string result = lfm.Scrobble(scrobbles, scrobbleType); dynamic resp = null; // No response, service must be offline if (result == null) { processor.WriteJson(new ScrobbleResponse("LFMServiceOffline")); return; } // If result is not null, store deserialize and store it try { resp = JsonConvert.DeserializeObject(result); } catch (Exception e) { logger.Error(e); } // Check for nowplaying or scrobbles fields if ((resp.nowplaying != null) || (resp.scrobbles != null)) { // Write blank scrobble response processor.WriteJson(new ScrobbleResponse()); return; } // Write error JSON if it exists else if (resp.error != null) { processor.WriteJson(new ScrobbleResponse(string.Format("LFM{0}: {1}", resp.error, resp.message))); return; } }
public override void Run() { try { string ffmpegArguments = "-loglevel quiet -i \"" + Item.FilePath() + "\" -f wav -"; logger.IfInfo("Forking the process"); logger.IfInfo("ffmpeg " + ffmpegArguments); // Create the ffmpeg process FfmpegProcess = new Process(); FfmpegProcess.StartInfo.FileName = "ffmpeg"; FfmpegProcess.StartInfo.Arguments = ffmpegArguments; FfmpegProcess.StartInfo.UseShellExecute = false; FfmpegProcess.StartInfo.RedirectStandardOutput = true; FfmpegProcess.StartInfo.RedirectStandardError = true; // Create the opusenc object logger.IfInfo("opusenc " + Arguments); TranscodeProcess = new Process(); TranscodeProcess.StartInfo.FileName = "opusenc"; TranscodeProcess.StartInfo.Arguments = Arguments; TranscodeProcess.StartInfo.UseShellExecute = false; TranscodeProcess.StartInfo.RedirectStandardInput = true; TranscodeProcess.StartInfo.RedirectStandardOutput = true; TranscodeProcess.StartInfo.RedirectStandardError = false; var buffer = new byte[8192]; FfmpegProcess.Start(); TranscodeProcess.Start(); var input = new BinaryWriter(TranscodeProcess.StandardInput.BaseStream); int totalWritten = 0; while (true) { int bytesRead = FfmpegProcess.StandardOutput.BaseStream.Read(buffer, 0, 8192); totalWritten += bytesRead; if (bytesRead > 0) { input.Write(buffer, 0, bytesRead); } if (bytesRead == 0 && FfmpegProcess.HasExited) { input.Close(); FfmpegProcess.Close(); break; } } logger.IfInfo("Waiting for processes to finish"); // Block until done TranscodeProcess.WaitForExit(); logger.IfInfo("Process finished"); } catch (Exception e) { logger.IfInfo("\t" + "Failed to start transcode process " + e); try { TranscodeProcess.Kill(); TranscodeProcess.Close(); } catch { /* do nothing if killing the process fails */ } try { FfmpegProcess.Kill(); FfmpegProcess.Close(); } catch { /* do nothing if killing the process fails */ } // Set the state State = TranscodeState.Failed; // Inform the delegate if ((object)TranscoderDelegate != null) { TranscoderDelegate.TranscodeFailed(this); } return; } if (TranscodeProcess != null) { int exitValue = TranscodeProcess.ExitCode; logger.IfInfo("Exit value " + exitValue); if (exitValue == 0) { State = TranscodeState.Finished; if ((object)TranscoderDelegate != null) { TranscoderDelegate.TranscodeFinished(this); } } else { State = TranscodeState.Failed; if ((object)TranscoderDelegate != null) { TranscoderDelegate.TranscodeFailed(this); } } } }
public override void Start() { // Stopwatches to track scanning times Stopwatch testTotalScanTime = new Stopwatch(); Stopwatch testArtistScanTime = new Stopwatch(); Stopwatch testAlbumArtistScanTime = new Stopwatch(); // Dictionary of artists and existing IDs IDictionary <string, string> existingIds = new Dictionary <string, string>(); // List of artists who don't have IDs IList <Artist> artistsMissingId = new List <Artist>(); logger.IfInfo("------------- MUSICBRAINZ SCAN -------------"); testTotalScanTime.Start(); // Find artists and album artists missing ids, and all existing musicbrainz ids, to avoid extra lookups IArtistRepository artistRepository = Injection.Kernel.Get <IArtistRepository>(); IList <Artist> allArtists = artistRepository.AllArtists(); foreach (Artist artist in allArtists) { if (artist.MusicBrainzId == null) { artistsMissingId.Add(artist); } else { existingIds[artist.ArtistName] = artist.MusicBrainzId; } } IList <AlbumArtist> albumArtistsMissingId = new List <AlbumArtist>(); IAlbumArtistRepository albumArtistRepository = Injection.Kernel.Get <IAlbumArtistRepository>(); IList <AlbumArtist> allAlbumArtists = albumArtistRepository.AllAlbumArtists(); foreach (AlbumArtist albumArtist in allAlbumArtists) { if (albumArtist.MusicBrainzId == null) { albumArtistsMissingId.Add(albumArtist); } else { existingIds[albumArtist.AlbumArtistName] = albumArtist.MusicBrainzId; } } testArtistScanTime.Start(); int artistCount = this.ScanArtists(existingIds, artistsMissingId); testArtistScanTime.Stop(); testAlbumArtistScanTime.Start(); int albumArtistCount = this.ScanAlbumArtists(existingIds, albumArtistsMissingId); testAlbumArtistScanTime.Stop(); testTotalScanTime.Stop(); logger.IfInfo("------------- MUSICBRAINZ SCAN -------------"); logger.IfInfo("total scan time: " + testTotalScanTime.ElapsedMilliseconds + "ms"); logger.IfInfo("---------------------------------------------"); logger.IfInfo("artist IDs retrieved: " + artistCount); logger.IfInfo("artist scan time: " + testArtistScanTime.ElapsedMilliseconds + "ms"); logger.IfInfo("albumArtist IDs retrieved: " + albumArtistCount); logger.IfInfo("albumArtist scan time: " + testAlbumArtistScanTime.ElapsedMilliseconds + "ms"); logger.IfInfo("---------------------------------------------"); }
/// <summary> /// Add a new service, by name, to the manager, optionally starting it automatically /// </summary> public static bool Add(string name, bool autostart = false) { // Ensure lowercase names name = name.ToLower(); // Check if service is disabled if (name[0] == '!') { logger.IfInfo("Skipping disabled service: " + name); return(true); } // Check if service is already present in list if (Services.Any(x => x.Name == name)) { logger.IfInfo("Skipping duplicate service: " + name); return(false); } // Generate service from name IService service = ServiceFactory.CreateService(name); // Ensure service was valid if ((object)service == null) { logger.Error("Unknown service: " + name); return(false); } // Add service to list Services.Add(service); // Autostart if requested if (autostart) { if (!Start(service)) { logger.Error("Failed to autostart service: " + service.Name); return(false); } } return(true); }
/// <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(); }
/// <summary> /// Process returns an AlbumArtistsResponse containing a list of artists, albums, and songs /// </summary> public void Process(UriWrapper uri, IHttpProcessor processor, User user) { // Lists of artists, albums, songs to be returned via handler IList <AlbumArtist> albumArtists = new List <AlbumArtist>(); IList <Album> albums = new List <Album>(); IList <Song> songs = new List <Song>(); Dictionary <string, int> counts = new Dictionary <string, int>(); PairList <string, int> sectionPositions = new PairList <string, int>(); // Optional Last.fm info string lastfmInfo = null; // Check if an ID was passed if (uri.Id != null) { // Add artist by ID to the list AlbumArtist a = Injection.Kernel.Get <IAlbumArtistRepository>().AlbumArtistForId((int)uri.Id); albumArtists.Add(a); // Add artist's albums to response albums = a.ListOfAlbums(); counts.Add("albums", albums.Count); // If requested, add artist's songs to response if (uri.Parameters.ContainsKey("includeSongs") && uri.Parameters["includeSongs"].IsTrue()) { songs = a.ListOfSongs(); counts.Add("songs", songs.Count); } else { counts.Add("songs", a.ListOfSongs().Count); } // If requested, add artist's Last.fm info to response if (uri.Parameters.ContainsKey("lastfmInfo") && uri.Parameters["lastfmInfo"].IsTrue()) { logger.IfInfo("Querying Last.fm for artist: " + a.AlbumArtistName); try { lastfmInfo = Lastfm.GetAlbumArtistInfo(a); logger.IfInfo("Last.fm query complete!"); } catch (Exception e) { logger.Error("Last.fm query failed!"); logger.Error(e); } } // Get favorites count if available if (a.AlbumArtistId != null) { int favoriteCount = Injection.Kernel.Get <IFavoriteRepository>().FavoritesForAlbumArtistId(a.AlbumArtistId, user.UserId).Count; counts.Add("favorites", favoriteCount); } else { counts.Add("favorites", 0); } } // Check for a request for range of artists else if (uri.Parameters.ContainsKey("range")) { string[] range = uri.Parameters["range"].Split(','); // Ensure valid range was parsed if (range.Length != 2) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'range' requires a valid, comma-separated character tuple", null, null, null, null, null, null)); return; } // Validate as characters char start, end; if (!Char.TryParse(range[0], out start) || !Char.TryParse(range[1], out end)) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'range' requires characters which are single alphanumeric values", null, null, null, null, null, null)); return; } // Grab range of artists albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().RangeAlbumArtists(start, end); } // Check for a request to limit/paginate artists, like SQL // Note: can be combined with range or all artists if (uri.Parameters.ContainsKey("limit") && uri.Id == null) { string[] limit = uri.Parameters["limit"].Split(','); // Ensure valid limit was parsed if (limit.Length < 1 || limit.Length > 2) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a single integer, or a valid, comma-separated integer tuple", null, null, null, null, null, null)); return; } // Validate as integers int index = 0; int duration = Int32.MinValue; if (!Int32.TryParse(limit[0], out index)) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a valid integer start index", null, null, null, null, null, null)); return; } // Ensure positive index if (index < 0) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a non-negative integer start index", null, null, null, null, null, null)); return; } // Check for duration if (limit.Length == 2) { if (!Int32.TryParse(limit[1], out duration)) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a valid integer duration", null, null, null, null, null, null)); return; } // Ensure positive duration if (duration < 0) { processor.WriteJson(new AlbumArtistsResponse("Parameter 'limit' requires a non-negative integer duration", null, null, null, null, null, null)); return; } } // Check if results list already populated by range if (albumArtists.Count > 0) { // No duration? Return just specified number of artists if (duration == Int32.MinValue) { albumArtists = albumArtists.Skip(0).Take(index).ToList(); } else { // Else, return artists starting at index, up to count duration albumArtists = albumArtists.Skip(index).Take(duration).ToList(); } } else { // If no artists in list, grab directly using model method albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().LimitAlbumArtists(index, duration); } } // Finally, if no artists already in list, send the whole list if (albumArtists.Count == 0) { albumArtists = Injection.Kernel.Get <IAlbumArtistRepository>().AllAlbumArtists(); sectionPositions = Utility.SectionPositionsFromSortedList(new List <IGroupingItem>(albumArtists.Select(c => (IGroupingItem)c))); } // Send it! processor.WriteJson(new AlbumArtistsResponse(null, albumArtists, albums, songs, counts, lastfmInfo, sectionPositions)); return; }
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); }