mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-04 03:27:21 -05:00 
			
		
		
		
	Added initial implementation of the metadata provider network, along with the first few providers
This commit is contained in:
		
							parent
							
								
									803ce0968e
								
							
						
					
					
						commit
						d794eecec4
					
				@ -12,6 +12,7 @@ using MediaBrowser.Common.Net;
 | 
				
			|||||||
using MediaBrowser.Common.Plugins;
 | 
					using MediaBrowser.Common.Plugins;
 | 
				
			||||||
using MediaBrowser.Common.Serialization;
 | 
					using MediaBrowser.Common.Serialization;
 | 
				
			||||||
using MediaBrowser.Model.Progress;
 | 
					using MediaBrowser.Model.Progress;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.Common.Kernel
 | 
					namespace MediaBrowser.Common.Kernel
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -51,7 +52,9 @@ namespace MediaBrowser.Common.Kernel
 | 
				
			|||||||
            ApplicationPaths = new TApplicationPathsType();
 | 
					            ApplicationPaths = new TApplicationPathsType();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public virtual void Init(IProgress<TaskProgress> progress)
 | 
					        public virtual Task Init(IProgress<TaskProgress> progress)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Task.Run(() =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ReloadLogger();
 | 
					                ReloadLogger();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -63,6 +66,7 @@ namespace MediaBrowser.Common.Kernel
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                progress.Report(new TaskProgress() { Description = "Loading Plugins", PercentComplete = 10 });
 | 
					                progress.Report(new TaskProgress() { Description = "Loading Plugins", PercentComplete = 10 });
 | 
				
			||||||
                ReloadComposableParts();
 | 
					                ReloadComposableParts();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
 | 
				
			|||||||
@ -151,6 +151,50 @@ namespace MediaBrowser.Controller.Configuration
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private string _CacheDirectory = null;
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Gets the folder path to the cache directory
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public string CacheDirectory
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            get
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_CacheDirectory == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _CacheDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.ProgramDataPath, "cache");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (!Directory.Exists(_CacheDirectory))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Directory.CreateDirectory(_CacheDirectory);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return _CacheDirectory;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private string _FFProbeAudioCacheDirectory = null;
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Gets the folder path to the ffprobe audio cache directory
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public string FFProbeAudioCacheDirectory
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            get
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (_FFProbeAudioCacheDirectory == null)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _FFProbeAudioCacheDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.CacheDirectory, "ffprobe-audio");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (!Directory.Exists(_FFProbeAudioCacheDirectory))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        Directory.CreateDirectory(_FFProbeAudioCacheDirectory);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return _FFProbeAudioCacheDirectory;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        private string _FFMpegDirectory = null;
 | 
					        private string _FFMpegDirectory = null;
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets the folder path to ffmpeg
 | 
					        /// Gets the folder path to ffmpeg
 | 
				
			||||||
@ -221,7 +265,7 @@ namespace MediaBrowser.Controller.Configuration
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    _FFProbePath = Path.Combine(FFMpegDirectory, filename);
 | 
					                    _FFProbePath = Path.Combine(FFMpegDirectory, filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // Always re-extract the first time to handle new versions
 | 
					                    /*// Always re-extract the first time to handle new versions
 | 
				
			||||||
                    if (File.Exists(_FFProbePath))
 | 
					                    if (File.Exists(_FFProbePath))
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        File.Delete(_FFProbePath);
 | 
					                        File.Delete(_FFProbePath);
 | 
				
			||||||
@ -234,7 +278,7 @@ namespace MediaBrowser.Controller.Configuration
 | 
				
			|||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            stream.CopyTo(fileStream);
 | 
					                            stream.CopyTo(fileStream);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }*/
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return _FFProbePath;
 | 
					                return _FFProbePath;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,41 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Diagnostics;
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using MediaBrowser.Common.Logging;
 | 
					using MediaBrowser.Common.Logging;
 | 
				
			||||||
using MediaBrowser.Common.Serialization;
 | 
					using MediaBrowser.Common.Serialization;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.Controller.FFMpeg
 | 
					namespace MediaBrowser.Controller.FFMpeg
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Runs FFProbe against a media file and returns metadata.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public static class FFProbe
 | 
					    public static class FFProbe
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public static FFProbeResult Run(string path)
 | 
					        public async static Task<FFProbeResult> Run(Audio item, string outputCachePath)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // Use try catch to avoid having to use File.Exists
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                using (FileStream stream = File.OpenRead(outputCachePath))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    return JsonSerializer.DeserializeFromStream<FFProbeResult>(stream);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (FileNotFoundException)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await Run(item.Path, outputCachePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            using (FileStream stream = File.OpenRead(outputCachePath))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return JsonSerializer.DeserializeFromStream<FFProbeResult>(stream);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async static Task Run(string input, string output)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ProcessStartInfo startInfo = new ProcessStartInfo();
 | 
					            ProcessStartInfo startInfo = new ProcessStartInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -21,13 +49,15 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            startInfo.FileName = Kernel.Instance.ApplicationPaths.FFProbePath;
 | 
					            startInfo.FileName = Kernel.Instance.ApplicationPaths.FFProbePath;
 | 
				
			||||||
            startInfo.WorkingDirectory = Kernel.Instance.ApplicationPaths.FFMpegDirectory;
 | 
					            startInfo.WorkingDirectory = Kernel.Instance.ApplicationPaths.FFMpegDirectory;
 | 
				
			||||||
            startInfo.Arguments = string.Format("\"{0}\" -v quiet -print_format json -show_streams -show_format", path);
 | 
					            startInfo.Arguments = string.Format("\"{0}\" -v quiet -print_format json -show_streams -show_format", input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
 | 
					            //Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Process process = new Process();
 | 
					            Process process = new Process();
 | 
				
			||||||
            process.StartInfo = startInfo;
 | 
					            process.StartInfo = startInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            FileStream stream = new FileStream(output, FileMode.Create);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                process.Start();
 | 
					                process.Start();
 | 
				
			||||||
@ -36,18 +66,23 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
                // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
 | 
					                // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
 | 
				
			||||||
                process.BeginErrorReadLine();
 | 
					                process.BeginErrorReadLine();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                FFProbeResult result = JsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream);
 | 
					                await process.StandardOutput.BaseStream.CopyToAsync(stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                process.WaitForExit();
 | 
					                process.WaitForExit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Logger.LogInfo("FFMpeg exited with code " + process.ExitCode);
 | 
					                stream.Dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return result;
 | 
					                if (process.ExitCode != 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Logger.LogInfo("FFProbe exited with code {0} for {1}", process.ExitCode, input);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Logger.LogException(ex);
 | 
					                Logger.LogException(ex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                stream.Dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Hate having to do this
 | 
					                // Hate having to do this
 | 
				
			||||||
                try
 | 
					                try
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -56,8 +91,7 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
                catch
 | 
					                catch
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                File.Delete(output);
 | 
				
			||||||
                return null;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            finally
 | 
					            finally
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,11 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
        public MediaFormat format { get; set; }
 | 
					        public MediaFormat format { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Represents a stream within the output
 | 
				
			||||||
 | 
					    /// A number of properties are commented out to improve deserialization performance
 | 
				
			||||||
 | 
					    /// Enable them as needed.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
    public class MediaStream
 | 
					    public class MediaStream
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int index { get; set; }
 | 
					        public int index { get; set; }
 | 
				
			||||||
@ -20,28 +25,28 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
        public string codec_name { get; set; }
 | 
					        public string codec_name { get; set; }
 | 
				
			||||||
        public string codec_long_name { get; set; }
 | 
					        public string codec_long_name { get; set; }
 | 
				
			||||||
        public string codec_type { get; set; }
 | 
					        public string codec_type { get; set; }
 | 
				
			||||||
        public string codec_time_base { get; set; }
 | 
					        //public string codec_time_base { get; set; }
 | 
				
			||||||
        public string codec_tag { get; set; }
 | 
					        //public string codec_tag { get; set; }
 | 
				
			||||||
        public string codec_tag_string { get; set; }
 | 
					        //public string codec_tag_string { get; set; }
 | 
				
			||||||
        public string sample_fmt { get; set; }
 | 
					        //public string sample_fmt { get; set; }
 | 
				
			||||||
        public string sample_rate { get; set; }
 | 
					        public string sample_rate { get; set; }
 | 
				
			||||||
        public int channels { get; set; }
 | 
					        public int channels { get; set; }
 | 
				
			||||||
        public int bits_per_sample { get; set; }
 | 
					        //public int bits_per_sample { get; set; }
 | 
				
			||||||
        public string r_frame_rate { get; set; }
 | 
					        //public string r_frame_rate { get; set; }
 | 
				
			||||||
        public string avg_frame_rate { get; set; }
 | 
					        //public string avg_frame_rate { get; set; }
 | 
				
			||||||
        public string time_base { get; set; }
 | 
					        //public string time_base { get; set; }
 | 
				
			||||||
        public string start_time { get; set; }
 | 
					        //public string start_time { get; set; }
 | 
				
			||||||
        public string duration { get; set; }
 | 
					        public string duration { get; set; }
 | 
				
			||||||
        public string bit_rate { get; set; }
 | 
					        public string bit_rate { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int width { get; set; }
 | 
					        public int width { get; set; }
 | 
				
			||||||
        public int height { get; set; }
 | 
					        public int height { get; set; }
 | 
				
			||||||
        public int has_b_frames { get; set; }
 | 
					        //public int has_b_frames { get; set; }
 | 
				
			||||||
        public string sample_aspect_ratio { get; set; }
 | 
					        //public string sample_aspect_ratio { get; set; }
 | 
				
			||||||
        public string display_aspect_ratio { get; set; }
 | 
					        //public string display_aspect_ratio { get; set; }
 | 
				
			||||||
        public string pix_fmt { get; set; }
 | 
					        //public string pix_fmt { get; set; }
 | 
				
			||||||
        public int level { get; set; }
 | 
					        //public int level { get; set; }
 | 
				
			||||||
        public MediaTags tags { get; set; }
 | 
					        public Dictionary<string,string> tags { get; set; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class MediaFormat
 | 
					    public class MediaFormat
 | 
				
			||||||
@ -54,23 +59,6 @@ namespace MediaBrowser.Controller.FFMpeg
 | 
				
			|||||||
        public string duration { get; set; }
 | 
					        public string duration { get; set; }
 | 
				
			||||||
        public string size { get; set; }
 | 
					        public string size { get; set; }
 | 
				
			||||||
        public string bit_rate { get; set; }
 | 
					        public string bit_rate { get; set; }
 | 
				
			||||||
        public MediaTags tags { get; set; }
 | 
					        public Dictionary<string, string> tags { get; set; }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public class MediaTags
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public string title { get; set; }
 | 
					 | 
				
			||||||
        public string comment { get; set; }
 | 
					 | 
				
			||||||
        public string artist { get; set; }
 | 
					 | 
				
			||||||
        public string album { get; set; }
 | 
					 | 
				
			||||||
        public string album_artist { get; set; }
 | 
					 | 
				
			||||||
        public string composer { get; set; }
 | 
					 | 
				
			||||||
        public string copyright { get; set; }
 | 
					 | 
				
			||||||
        public string publisher { get; set; }
 | 
					 | 
				
			||||||
        public string track { get; set; }
 | 
					 | 
				
			||||||
        public string disc { get; set; }
 | 
					 | 
				
			||||||
        public string genre { get; set; }
 | 
					 | 
				
			||||||
        public string date { get; set; }
 | 
					 | 
				
			||||||
        public string language { get; set; }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -88,7 +88,7 @@ namespace MediaBrowser.Controller.IO
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void ProcessPathChanges(IEnumerable<string> paths)
 | 
					        private void ProcessPathChanges(IEnumerable<string> paths)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<BaseItem> itemsToRefresh = new List<BaseItem>();
 | 
					            /*List<BaseItem> itemsToRefresh = new List<BaseItem>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            foreach (BaseItem item in paths.Select(p => GetAffectedBaseItem(p)))
 | 
					            foreach (BaseItem item in paths.Select(p => GetAffectedBaseItem(p)))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -113,7 +113,7 @@ namespace MediaBrowser.Controller.IO
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    Kernel.Instance.ReloadItem(itemsToRefresh[i]);
 | 
					                    Kernel.Instance.ReloadItem(itemsToRefresh[i]);
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }*/
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private BaseItem GetAffectedBaseItem(string path)
 | 
					        private BaseItem GetAffectedBaseItem(string path)
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,13 @@ using System.IO;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Security.Cryptography;
 | 
					using System.Security.Cryptography;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using MediaBrowser.Common.Kernel;
 | 
					using MediaBrowser.Common.Kernel;
 | 
				
			||||||
using MediaBrowser.Controller.Configuration;
 | 
					using MediaBrowser.Controller.Configuration;
 | 
				
			||||||
using MediaBrowser.Controller.Events;
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
using MediaBrowser.Controller.IO;
 | 
					using MediaBrowser.Controller.IO;
 | 
				
			||||||
using MediaBrowser.Controller.Library;
 | 
					using MediaBrowser.Controller.Library;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Providers;
 | 
				
			||||||
using MediaBrowser.Controller.Resolvers;
 | 
					using MediaBrowser.Controller.Resolvers;
 | 
				
			||||||
using MediaBrowser.Model.Entities;
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
using MediaBrowser.Model.Progress;
 | 
					using MediaBrowser.Model.Progress;
 | 
				
			||||||
@ -35,6 +37,12 @@ namespace MediaBrowser.Controller
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Gets the list of currently registered metadata prvoiders
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        [ImportMany(typeof(BaseMetadataProvider))]
 | 
				
			||||||
 | 
					        public IEnumerable<BaseMetadataProvider> MetadataProviders { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets the list of currently registered entity resolvers
 | 
					        /// Gets the list of currently registered entity resolvers
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@ -56,35 +64,63 @@ namespace MediaBrowser.Controller
 | 
				
			|||||||
            ItemController.BeginResolvePath += ItemController_BeginResolvePath;
 | 
					            ItemController.BeginResolvePath += ItemController_BeginResolvePath;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public override void Init(IProgress<TaskProgress> progress)
 | 
					        public async override Task Init(IProgress<TaskProgress> progress)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            base.Init(progress);
 | 
					            await base.Init(progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            progress.Report(new TaskProgress() { Description = "Loading Users", PercentComplete = 15 });
 | 
					            progress.Report(new TaskProgress() { Description = "Loading Users", PercentComplete = 15 });
 | 
				
			||||||
            ReloadUsers();
 | 
					            ReloadUsers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            progress.Report(new TaskProgress() { Description = "Loading Media Library", PercentComplete = 20 });
 | 
					            progress.Report(new TaskProgress() { Description = "Loading Media Library", PercentComplete = 20 });
 | 
				
			||||||
            ReloadRoot();
 | 
					            await ReloadRoot();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            progress.Report(new TaskProgress() { Description = "Loading Complete", PercentComplete = 100 });
 | 
					            progress.Report(new TaskProgress() { Description = "Loading Complete", PercentComplete = 100 });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override void OnComposablePartsLoaded()
 | 
					        protected override void OnComposablePartsLoaded()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<IBaseItemResolver> resolvers = EntityResolvers.ToList();
 | 
					            AddCoreResolvers();
 | 
				
			||||||
 | 
					            AddCoreProviders();
 | 
				
			||||||
            // Add the internal resolvers
 | 
					 | 
				
			||||||
            resolvers.Add(new VideoResolver());
 | 
					 | 
				
			||||||
            resolvers.Add(new AudioResolver());
 | 
					 | 
				
			||||||
            resolvers.Add(new VirtualFolderResolver());
 | 
					 | 
				
			||||||
            resolvers.Add(new FolderResolver());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            EntityResolvers = resolvers;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // The base class will start up all the plugins
 | 
					            // The base class will start up all the plugins
 | 
				
			||||||
            base.OnComposablePartsLoaded();
 | 
					            base.OnComposablePartsLoaded();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void AddCoreResolvers()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<IBaseItemResolver> list = EntityResolvers.ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add the core resolvers
 | 
				
			||||||
 | 
					            list.AddRange(new IBaseItemResolver[]{
 | 
				
			||||||
 | 
					                new AudioResolver(),
 | 
				
			||||||
 | 
					                new VideoResolver(),
 | 
				
			||||||
 | 
					                new VirtualFolderResolver(),
 | 
				
			||||||
 | 
					                new FolderResolver()
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            EntityResolvers = list;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void AddCoreProviders()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<BaseMetadataProvider> list = MetadataProviders.ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add the core resolvers
 | 
				
			||||||
 | 
					            list.InsertRange(0, new BaseMetadataProvider[]{
 | 
				
			||||||
 | 
					                new ImageFromMediaLocationProvider(),
 | 
				
			||||||
 | 
					                new LocalTrailerProvider(),
 | 
				
			||||||
 | 
					                new AudioInfoProvider(),
 | 
				
			||||||
 | 
					                new FolderProviderFromXml()
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            MetadataProviders = list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Parallel.ForEach(MetadataProviders, provider =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                provider.Init();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Fires when a path is about to be resolved, but before child folders and files 
 | 
					        /// Fires when a path is about to be resolved, but before child folders and files 
 | 
				
			||||||
        /// have been collected from the file system.
 | 
					        /// have been collected from the file system.
 | 
				
			||||||
@ -129,7 +165,7 @@ namespace MediaBrowser.Controller
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Reloads the root media folder
 | 
					        /// Reloads the root media folder
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public void ReloadRoot()
 | 
					        public async Task ReloadRoot()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!Directory.Exists(MediaRootFolderPath))
 | 
					            if (!Directory.Exists(MediaRootFolderPath))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -138,7 +174,7 @@ namespace MediaBrowser.Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            DirectoryWatchers.Stop();
 | 
					            DirectoryWatchers.Stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RootFolder = ItemController.GetItem(MediaRootFolderPath) as Folder;
 | 
					            RootFolder = await ItemController.GetItem(null, MediaRootFolderPath) as Folder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            DirectoryWatchers.Start();
 | 
					            DirectoryWatchers.Start();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -152,23 +188,23 @@ namespace MediaBrowser.Controller
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void ReloadItem(BaseItem item)
 | 
					        public async Task ReloadItem(BaseItem item)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Folder folder = item as Folder;
 | 
					            Folder folder = item as Folder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (folder != null && folder.IsRoot)
 | 
					            if (folder != null && folder.IsRoot)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ReloadRoot();
 | 
					                await ReloadRoot();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!Directory.Exists(item.Path) && !File.Exists(item.Path))
 | 
					                if (!Directory.Exists(item.Path) && !File.Exists(item.Path))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    ReloadItem(item.Parent);
 | 
					                    await ReloadItem(item.Parent);
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                BaseItem newItem = ItemController.GetItem(item.Parent, item.Path);
 | 
					                BaseItem newItem = await ItemController.GetItem(item.Parent, item.Path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                List<BaseItem> children = item.Parent.Children.ToList();
 | 
					                List<BaseItem> children = item.Parent.Children.ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,8 +3,6 @@ using System.Collections.Generic;
 | 
				
			|||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using MediaBrowser.Common.Configuration;
 | 
					 | 
				
			||||||
using MediaBrowser.Common.Events;
 | 
					 | 
				
			||||||
using MediaBrowser.Controller.Events;
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
using MediaBrowser.Controller.IO;
 | 
					using MediaBrowser.Controller.IO;
 | 
				
			||||||
using MediaBrowser.Controller.Resolvers;
 | 
					using MediaBrowser.Controller.Resolvers;
 | 
				
			||||||
@ -58,67 +56,12 @@ namespace MediaBrowser.Controller.Library
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region BaseItem Events
 | 
					        private async Task<BaseItem> ResolveItem(ItemResolveEventArgs args)
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when an item is being created.
 | 
					 | 
				
			||||||
        /// This should be used to fill item values, such as metadata
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        public event EventHandler<GenericItemEventArgs<BaseItem>> BaseItemCreating;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when an item has been created.
 | 
					 | 
				
			||||||
        /// This should be used to process or modify item values.
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        public event EventHandler<GenericItemEventArgs<BaseItem>> BaseItemCreated;
 | 
					 | 
				
			||||||
        #endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Called when an item has been created
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        private void OnBaseItemCreated(BaseItem item, Folder parent)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            GenericItemEventArgs<BaseItem> args = new GenericItemEventArgs<BaseItem> { Item = item };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (BaseItemCreating != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                BaseItemCreating(this, args);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (BaseItemCreated != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                BaseItemCreated(this, args);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void FireCreateEventsRecursive(Folder folder, Folder parent)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            OnBaseItemCreated(folder, parent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            int count = folder.Children.Length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Parallel.For(0, count, i =>
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                BaseItem item = folder.Children[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Folder childFolder = item as Folder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (childFolder != null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    FireCreateEventsRecursive(childFolder, folder);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    OnBaseItemCreated(item, folder);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private BaseItem ResolveItem(ItemResolveEventArgs args)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // If that didn't pan out, try the slow ones
 | 
					            // If that didn't pan out, try the slow ones
 | 
				
			||||||
            foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers)
 | 
					            foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var item = resolver.ResolvePath(args);
 | 
					                var item = await resolver.ResolvePath(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (item != null)
 | 
					                if (item != null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -132,39 +75,15 @@ namespace MediaBrowser.Controller.Library
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Resolves a path into a BaseItem
 | 
					        /// Resolves a path into a BaseItem
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public BaseItem GetItem(string path)
 | 
					        public async Task<BaseItem> GetItem(Folder parent, string path)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return GetItem(null, path);
 | 
					            return await GetItemInternal(parent, path, File.GetAttributes(path));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Resolves a path into a BaseItem
 | 
					        /// Resolves a path into a BaseItem
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public BaseItem GetItem(Folder parent, string path)
 | 
					        private async Task<BaseItem> GetItemInternal(Folder parent, string path, FileAttributes attributes)
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            BaseItem item = GetItemInternal(parent, path, File.GetAttributes(path));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (item != null)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var folder = item as Folder;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (folder != null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    FireCreateEventsRecursive(folder, parent);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    OnBaseItemCreated(item, parent);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return item;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Resolves a path into a BaseItem
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        private BaseItem GetItemInternal(Folder parent, string path, FileAttributes attributes)
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!OnPreBeginResolvePath(parent, path, attributes))
 | 
					            if (!OnPreBeginResolvePath(parent, path, attributes))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -201,14 +120,14 @@ namespace MediaBrowser.Controller.Library
 | 
				
			|||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            BaseItem item = ResolveItem(args);
 | 
					            BaseItem item = await ResolveItem(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var folder = item as Folder;
 | 
					            var folder = item as Folder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (folder != null)
 | 
					            if (folder != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // If it's a folder look for child entities
 | 
					                // If it's a folder look for child entities
 | 
				
			||||||
                AttachChildren(folder, fileSystemChildren);
 | 
					                await AttachChildren(folder, fileSystemChildren);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return item;
 | 
					            return item;
 | 
				
			||||||
@ -217,30 +136,25 @@ namespace MediaBrowser.Controller.Library
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Finds child BaseItems for a given Folder
 | 
					        /// Finds child BaseItems for a given Folder
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        private void AttachChildren(Folder folder, IEnumerable<KeyValuePair<string, FileAttributes>> fileSystemChildren)
 | 
					        private async Task AttachChildren(Folder folder, IEnumerable<KeyValuePair<string, FileAttributes>> fileSystemChildren)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<BaseItem> baseItemChildren = new List<BaseItem>();
 | 
					            KeyValuePair<string, FileAttributes>[] fileSystemChildrenArray = fileSystemChildren.ToArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int count = fileSystemChildren.Count();
 | 
					            int count = fileSystemChildrenArray.Length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Resolve the child folder paths into entities
 | 
					            Task<BaseItem>[] tasks = new Task<BaseItem>[count];
 | 
				
			||||||
            Parallel.For(0, count, i =>
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i < count; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                KeyValuePair<string, FileAttributes> child = fileSystemChildren.ElementAt(i);
 | 
					                var child = fileSystemChildrenArray[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                BaseItem item = GetItemInternal(folder, child.Key, child.Value);
 | 
					                tasks[i] = GetItemInternal(folder, child.Key, child.Value);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (item != null)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    lock (baseItemChildren)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        baseItemChildren.Add(item);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                }
 | 
					
 | 
				
			||||||
            });
 | 
					            BaseItem[] baseItemChildren = await Task<BaseItem>.WhenAll(tasks);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            // Sort them
 | 
					            // Sort them
 | 
				
			||||||
            folder.Children = baseItemChildren.OrderBy(f =>
 | 
					            folder.Children = baseItemChildren.Where(i => i != null).OrderBy(f =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName;
 | 
					                return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -363,7 +277,7 @@ namespace MediaBrowser.Controller.Library
 | 
				
			|||||||
        /// Creates an IBN item based on a given path
 | 
					        /// Creates an IBN item based on a given path
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        private T CreateImagesByNameItem<T>(string path, string name)
 | 
					        private T CreateImagesByNameItem<T>(string path, string name)
 | 
				
			||||||
            where T : BaseEntity, new ()
 | 
					            where T : BaseEntity, new()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            T item = new T();
 | 
					            T item = new T();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -59,6 +59,11 @@
 | 
				
			|||||||
    <Compile Include="Library\ItemController.cs" />
 | 
					    <Compile Include="Library\ItemController.cs" />
 | 
				
			||||||
    <Compile Include="Kernel.cs" />
 | 
					    <Compile Include="Kernel.cs" />
 | 
				
			||||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
					    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Providers\BaseMetadataProvider.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Providers\AudioInfoProvider.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Providers\FolderProviderFromXml.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Providers\ImageFromMediaLocationProvider.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Providers\LocalTrailerProvider.cs" />
 | 
				
			||||||
    <Compile Include="Resolvers\AudioResolver.cs" />
 | 
					    <Compile Include="Resolvers\AudioResolver.cs" />
 | 
				
			||||||
    <Compile Include="Resolvers\BaseItemResolver.cs" />
 | 
					    <Compile Include="Resolvers\BaseItemResolver.cs" />
 | 
				
			||||||
    <Compile Include="Resolvers\FolderResolver.cs" />
 | 
					    <Compile Include="Resolvers\FolderResolver.cs" />
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										86
									
								
								MediaBrowser.Controller/Providers/AudioInfoProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								MediaBrowser.Controller/Providers/AudioInfoProvider.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.ComponentModel.Composition;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.FFMpeg;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MediaBrowser.Controller.Providers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Export(typeof(BaseMetadataProvider))]
 | 
				
			||||||
 | 
					    public class AudioInfoProvider : BaseMetadataProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool Supports(BaseItem item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return item is Audio;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public async override Task Fetch(BaseItem item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Audio audio = item as Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, item.Id.ToString().Substring(0, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            string outputPath = Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            FFProbeResult data = await FFProbe.Run(audio, outputPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            MediaStream stream = data.streams.FirstOrDefault(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            audio.Channels = stream.channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            string bitrate = null;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if (!string.IsNullOrEmpty(stream.sample_rate))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                audio.SampleRate = int.Parse(stream.sample_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                bitrate = stream.bit_rate;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(bitrate))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                bitrate = data.format.bit_rate;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!string.IsNullOrEmpty(bitrate))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                audio.BitRate = int.Parse(bitrate);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private string GetOutputCachePath(BaseItem item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            string outputDirectory = Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, item.Id.ToString().Substring(0, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".js");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override void Init()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            base.Init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (int i = 0; i <= 9; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, i.ToString()));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "a"));
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "b"));
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "c"));
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "d"));
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "e"));
 | 
				
			||||||
 | 
					            EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, "f"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void EnsureDirectory(string path)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!Directory.Exists(path))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Directory.CreateDirectory(path);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								MediaBrowser.Controller/Providers/BaseMetadataProvider.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MediaBrowser.Controller.Providers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public abstract class BaseMetadataProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// If the provider needs any startup routines, add them here
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        public virtual void Init()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public virtual bool Supports(BaseItem item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public abstract Task Fetch(BaseItem item, ItemResolveEventArgs args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								MediaBrowser.Controller/Providers/FolderProviderFromXml.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					using System.ComponentModel.Composition;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Xml;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MediaBrowser.Controller.Providers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Export(typeof(BaseMetadataProvider))]
 | 
				
			||||||
 | 
					    public class FolderProviderFromXml : BaseMetadataProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override bool Supports(BaseItem item)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return item is Folder;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public override Task Fetch(BaseItem item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Task.Run(() =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var metadataFile = args.GetFileByName("folder.xml");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (metadataFile.HasValue)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new FolderXmlParser().Fetch(item as Folder, metadataFile.Value.Key);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.Composition;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MediaBrowser.Controller.Providers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Export(typeof(BaseMetadataProvider))]
 | 
				
			||||||
 | 
					    public class ImageFromMediaLocationProvider : BaseMetadataProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public override Task Fetch(BaseItem item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Task.Run(() =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (args.IsFolder)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    PopulateImages(item, args);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Fills in image paths based on files win the folder
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        private void PopulateImages(BaseItem item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<string> backdropFiles = new List<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (KeyValuePair<string, FileAttributes> file in args.FileSystemChildren)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (file.Value.HasFlag(FileAttributes.Directory))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                string filePath = file.Key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                string ext = Path.GetExtension(filePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Only support png and jpg files
 | 
				
			||||||
 | 
					                if (!ext.EndsWith("png", StringComparison.OrdinalIgnoreCase) && !ext.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                string name = Path.GetFileNameWithoutExtension(filePath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (name.Equals("folder", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.PrimaryImagePath = filePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else if (name.StartsWith("backdrop", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    backdropFiles.Add(filePath);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (name.Equals("logo", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.LogoImagePath = filePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (name.Equals("banner", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.BannerImagePath = filePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (name.Equals("art", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.ArtImagePath = filePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (name.Equals("thumb", StringComparison.OrdinalIgnoreCase))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    item.ThumbnailImagePath = filePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (backdropFiles.Any())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                item.BackdropImagePaths = backdropFiles;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								MediaBrowser.Controller/Providers/LocalTrailerProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								MediaBrowser.Controller/Providers/LocalTrailerProvider.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.ComponentModel.Composition;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MediaBrowser.Controller.Providers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Export(typeof(BaseMetadataProvider))]
 | 
				
			||||||
 | 
					    public class LocalTrailerProvider : BaseMetadataProvider
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public async override Task Fetch(BaseItem item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var trailerPath = args.GetFolderByName("trailers");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (trailerPath.HasValue)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                List<Video> localTrailers = new List<Video>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (string file in allFiles)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    BaseItem child = await Kernel.Instance.ItemController.GetItem(null, file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Video video = child as Video;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (video != null)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        localTrailers.Add(video);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                item.LocalTrailers = localTrailers;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using MediaBrowser.Controller.Events;
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
 | 
					using MediaBrowser.Controller.Providers;
 | 
				
			||||||
using MediaBrowser.Model.Entities;
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.Controller.Resolvers
 | 
					namespace MediaBrowser.Controller.Resolvers
 | 
				
			||||||
@ -33,19 +33,15 @@ namespace MediaBrowser.Controller.Resolvers
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            item.Id = Kernel.GetMD5(item.Path);
 | 
					            item.Id = Kernel.GetMD5(item.Path);
 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            PopulateImages(item, args);
 | 
					 | 
				
			||||||
            PopulateLocalTrailers(item, args);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public BaseItem ResolvePath(ItemResolveEventArgs args)
 | 
					        public async Task<BaseItem> ResolvePath(ItemResolveEventArgs args)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            T item = Resolve(args);
 | 
					            T item = Resolve(args);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            if (item != null)
 | 
					            if (item != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // Set initial values on the newly resolved item
 | 
					                // Set initial values on the newly resolved item
 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                SetItemValues(item, args);
 | 
					                SetItemValues(item, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Make sure the item has a name
 | 
					                // Make sure the item has a name
 | 
				
			||||||
@ -53,11 +49,24 @@ namespace MediaBrowser.Controller.Resolvers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                // Make sure DateCreated and DateModified have values
 | 
					                // Make sure DateCreated and DateModified have values
 | 
				
			||||||
                EnsureDates(item);
 | 
					                EnsureDates(item);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                await FetchMetadataFromProviders(item, args);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return item;
 | 
					            return item;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async Task FetchMetadataFromProviders(T item, ItemResolveEventArgs args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (BaseMetadataProvider provider in Kernel.Instance.MetadataProviders)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (provider.Supports(item))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    await provider.Fetch(item, args);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void EnsureName(T item)
 | 
					        private void EnsureName(T item)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // If the subclass didn't supply a name, add it here
 | 
					            // If the subclass didn't supply a name, add it here
 | 
				
			||||||
@ -84,76 +93,6 @@ namespace MediaBrowser.Controller.Resolvers
 | 
				
			|||||||
                item.DateModified = Path.IsPathRooted(item.Path) ? File.GetLastWriteTime(item.Path) : DateTime.Now;
 | 
					                item.DateModified = Path.IsPathRooted(item.Path) ? File.GetLastWriteTime(item.Path) : DateTime.Now;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Fills in image paths based on files win the folder
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        protected virtual void PopulateImages(T item, ItemResolveEventArgs args)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            List<string> backdropFiles = new List<string>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            foreach (KeyValuePair<string,FileAttributes> file in args.FileSystemChildren)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if (file.Value.HasFlag(FileAttributes.Directory))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                string filePath = file.Key;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                string ext = Path.GetExtension(filePath);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Only support png and jpg files
 | 
					 | 
				
			||||||
                if (!ext.EndsWith("png", StringComparison.OrdinalIgnoreCase) && !ext.EndsWith("jpg", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                string name = Path.GetFileNameWithoutExtension(filePath);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (name.Equals("folder", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    item.PrimaryImagePath = filePath;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else if (name.StartsWith("backdrop", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    backdropFiles.Add(filePath);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (name.Equals("logo", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    item.LogoImagePath = filePath;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (name.Equals("banner", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    item.BannerImagePath = filePath;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (name.Equals("art", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    item.ArtImagePath = filePath;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (name.Equals("thumb", StringComparison.OrdinalIgnoreCase))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    item.ThumbnailImagePath = filePath;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (backdropFiles.Any())
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                item.BackdropImagePaths = backdropFiles;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected virtual void PopulateLocalTrailers(T item, ItemResolveEventArgs args)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var trailerPath = args.GetFolderByName("trailers");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (trailerPath.HasValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                item.LocalTrailers = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(f)).OfType<Video>();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@ -161,6 +100,6 @@ namespace MediaBrowser.Controller.Resolvers
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public interface IBaseItemResolver
 | 
					    public interface IBaseItemResolver
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        BaseItem ResolvePath(ItemResolveEventArgs args);
 | 
					        Task<BaseItem> ResolvePath(ItemResolveEventArgs args);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
using System.ComponentModel.Composition;
 | 
					using System.ComponentModel.Composition;
 | 
				
			||||||
using MediaBrowser.Controller.Events;
 | 
					using MediaBrowser.Controller.Events;
 | 
				
			||||||
using MediaBrowser.Controller.Xml;
 | 
					 | 
				
			||||||
using MediaBrowser.Model.Entities;
 | 
					using MediaBrowser.Model.Entities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.Controller.Resolvers
 | 
					namespace MediaBrowser.Controller.Resolvers
 | 
				
			||||||
@ -27,19 +26,6 @@ namespace MediaBrowser.Controller.Resolvers
 | 
				
			|||||||
            base.SetItemValues(item, args);
 | 
					            base.SetItemValues(item, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            item.IsRoot = args.Parent == null;
 | 
					            item.IsRoot = args.Parent == null;
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Read data from folder.xml, if it exists
 | 
					 | 
				
			||||||
            PopulateFolderMetadata(item, args);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void PopulateFolderMetadata(TItemType folder, ItemResolveEventArgs args)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var metadataFile = args.GetFileByName("folder.xml");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (metadataFile.HasValue)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                new FolderXmlParser().Fetch(folder, metadataFile.Value.Key);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,7 @@ namespace MediaBrowser.Movies.Resolvers
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
 | 
					                string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                item.SpecialFeatures = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(f)).OfType<Video>();
 | 
					                item.SpecialFeatures = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(null, f)).OfType<Video>();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 | 
					        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 | 
				
			||||||
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 | 
					        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 | 
				
			||||||
        xmlns:tb="http://www.hardcodet.net/taskbar"
 | 
					        xmlns:tb="http://www.hardcodet.net/taskbar"
 | 
				
			||||||
        Title="MainWindow" Height="350" Width="525" AllowsTransparency="True" Background="Transparent" WindowStyle="None" ShowInTaskbar="False" Loaded="MainWindow_Loaded">
 | 
					        Title="MainWindow" Height="350" Width="525" AllowsTransparency="True" Background="Transparent" WindowStyle="None" ShowInTaskbar="False">
 | 
				
			||||||
    <Grid>
 | 
					    <Grid>
 | 
				
			||||||
        <tb:TaskbarIcon Name="MbTaskbarIcon" IconSource="/Icons/Icon.ico" ToolTipText="MediaBrowser Server" Visibility="Hidden">
 | 
					        <tb:TaskbarIcon Name="MbTaskbarIcon" IconSource="/Icons/Icon.ico" ToolTipText="MediaBrowser Server" Visibility="Hidden">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@ using System.Windows;
 | 
				
			|||||||
using MediaBrowser.Common.Logging;
 | 
					using MediaBrowser.Common.Logging;
 | 
				
			||||||
using MediaBrowser.Controller;
 | 
					using MediaBrowser.Controller;
 | 
				
			||||||
using MediaBrowser.Model.Progress;
 | 
					using MediaBrowser.Model.Progress;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using MediaBrowser.Common.UI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.ServerApplication
 | 
					namespace MediaBrowser.ServerApplication
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -18,10 +20,10 @@ namespace MediaBrowser.ServerApplication
 | 
				
			|||||||
            LoadKernel();
 | 
					            LoadKernel();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void LoadKernel()
 | 
					        private async void LoadKernel()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Progress<TaskProgress> progress = new Progress<TaskProgress>();
 | 
					            Progress<TaskProgress> progress = new Progress<TaskProgress>();
 | 
				
			||||||
            Common.UI.Splash splash = new Common.UI.Splash(progress);
 | 
					            Splash splash = new Splash(progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            splash.Show();
 | 
					            splash.Show();
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
@ -29,11 +31,14 @@ namespace MediaBrowser.ServerApplication
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                DateTime now = DateTime.Now;
 | 
					                DateTime now = DateTime.Now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                new Kernel().Init(progress);
 | 
					                await new Kernel().Init(progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                double seconds = (DateTime.Now - now).TotalSeconds;
 | 
					                double seconds = (DateTime.Now - now).TotalSeconds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Logger.LogInfo("Kernel.Init completed in {0} seconds.", seconds);
 | 
					                Logger.LogInfo("Kernel.Init completed in {0} seconds.", seconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Don't show the system tray icon until the kernel finishes.
 | 
				
			||||||
 | 
					                this.MbTaskbarIcon.Visibility = System.Windows.Visibility.Visible;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (Exception ex)
 | 
					            catch (Exception ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -46,16 +51,6 @@ namespace MediaBrowser.ServerApplication
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region Main Window Events
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            // Don't show the system tray icon until the app has loaded.
 | 
					 | 
				
			||||||
            this.MbTaskbarIcon.Visibility = System.Windows.Visibility.Visible;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        #endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        #region Context Menu events
 | 
					        #region Context Menu events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void cmOpenDashboard_click(object sender, RoutedEventArgs e)
 | 
					        private void cmOpenDashboard_click(object sender, RoutedEventArgs e)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user