/// <summary>
        /// Instantiate a new playlist writer based on the specified key.
        /// </summary>
        /// <param name="key">The key identifying the writer.</param>
        /// <param name="root">The root path of the exported playlist.</param>
        /// <param name="name">The base name of this playlist file.</param>
        /// <param name="createSubdirectories">
        /// A Boolean value indicating whether files in this playlist are located relative
        /// to the root (<b>true</b>) or are all located within the root itself (<b>false</b>).
        /// </param>
        /// <returns>An IPlaylistWriter instance.</returns>

        public static IPlaylistWriter CreateWriter(
            string key, string root, string name, bool createSubdirectories)
        {
            IPlaylistWriter writer = null;

            switch (key)
            {
            case "M3U":
                writer = new M3UPlaylistWriter(root, name, createSubdirectories);
                break;

            case "PLS":
                writer = new PLSPlaylistWriter(root, name, createSubdirectories);
                break;

            case "WPL":
                writer = new WPLPlaylistWriter(root, name, createSubdirectories);
                break;

            case "ZPL":
                writer = new ZPLPlaylistWriter(root, name, createSubdirectories);
                break;
            }

            return(writer);
        }
        public void Export(string playlistType, bool excludeSmart, IPlaylistWriter playlistWriter)
        {
            var allPlaylists = GetAllPlaylistsOfType(playlistType, excludeSmart);

            var allPlaylistNames = allPlaylists.Select(xe => xe.Attribute("title")?.Value);

            Export(playlistType, allPlaylistNames, excludeSmart, playlistWriter);
        }
示例#3
0
        public void Export_CorrectInputs_Succeeds()
        {
            _playlistWriter = Substitute.For <IPlaylistWriter>();

            PlaylistExporter sut = new PlaylistExporter(_fileSystem, _playlistReader,
                                                        _playlistWriter);

            sut.Export(".\\TestData\\Laptop.m3u", "C:\\temp\\output",
                       "C:\\Users\\jfox\\Music\\iTunes\\iTunes Media\\Music", ExportMode.PlaylistContents);
        }
示例#4
0
        public void Export_PlaylistOnly_Succeeds()
        {
            _playlistWriter = new PlaylistWriter(
                new SensusPlaylistFormatter(_fileSystem));

            PlaylistExporter sut = new PlaylistExporter(_fileSystem, _playlistReader, _playlistWriter);

            sut.Export(".\\TestData\\Laptop.m3u", "C:\\temp\\output",
                       "C:\\Users\\jfox\\Music\\iTunes\\iTunes Media\\Music",
                       ExportMode.PlaylistFile);
        }
示例#5
0
        /// <summary>
        /// Initialize the environment for an export or synchronize operation.
        /// </summary>

        private void Initialize()
        {
            Logger.WriteLine(base.name,
                             String.Format("Export beginning, using encoder '{0}'",
                                           encoder == null ? "(skip)" : encoder.Name));

            // attach COM status handlers
            base.EnableInterrupt(controller);

            // override current encoder if different than requested
            if ((encoder != null) && !encoder.IsEmpty)
            {
                if (!controller.CurrentEncoder.Name.Equals(encoder.Name))
                {
                    // remember user's preferred encoder
                    saveEncoder = controller.CurrentEncoder;

                    // set the temporary encoder for this playlist
                    controller.CurrentEncoder = encoder;
                }
            }

            // ensure that 'location' exists before continuing.  This will be more efficient
            // for cases that do not require further subdirectories but also sets the stage...

            if (!Directory.Exists(location))
            {
                if (ScannerBase.isLive)
                {
                    Directory.CreateDirectory(location);
                }
            }

            // if we do want subdirectories then ensure we can create them
            if (!createSubdirectories)
            {
                createSubdirectories = EnsureFolderCapability();
            }

            // initialize and open the playlist writer if a playlist is requested
            if (ScannerBase.isLive && !playlistFormat.Equals(PlaylistProviderFactory.NoFormat))
            {
                writer = PlaylistProviderFactory.CreateWriter(
                    playlistFormat, location, exportPIDs.Name, createSubdirectories);
            }

            // this ManualResetEvent is used to synchronize sequential processing of iTunes
            // tracks as they are encoded.  iTunes encoding is an asynchronous procedure
            // however, iTunes does not allow concurrent encodings to occur.

            reset   = new ManualResetEvent(false);
            exports = new StringCollection();
        }
示例#6
0
        /// <summary>
        /// Cleanup anything started in Initialize.
        /// </summary>

        private void Cleanup()
        {
            // detach COM status handlers
            base.DisableInterrupt(controller);

            if (saveEncoder != null)
            {
                try
                {
                    // restore the iTunes encoder as specified in the user Preferences
                    controller.CurrentEncoder = saveEncoder;
                }
                catch
                {
                    // no-op
                }
            }

            if (encoder != null)
            {
                encoder.Dispose(true);
                encoder = null;
            }

            if (writer != null)
            {
                writer.Close();
                writer.Dispose();
                writer = null;
            }

            if (exports != null)
            {
                exports.Clear();
                exports = null;
            }

            if (reset != null)
            {
                reset.Dispose();
                reset = null;
            }

            base.ProgressPercentage = 100;
            base.UpdateProgress(Resx.Completed);

            Logger.WriteLine(base.name, "Export completed");
        }
示例#7
0
        public PlaylistExporter(IFileSystem fileSystem, IPlaylistReader playlistReader,
                                IPlaylistWriter playlistWriter)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }
            if (playlistReader == null)
            {
                throw new ArgumentNullException(nameof(playlistReader));
            }
            if (playlistWriter == null)
            {
                throw new ArgumentNullException(nameof(playlistWriter));
            }

            _fileSystem     = fileSystem;
            _playlistReader = playlistReader;
            _playlistWriter = playlistWriter;
        }
示例#8
0
        public MainWindow()
        {
            _audioDeviceLocater = new AudioDeviceLocater();

            //Load app configuration
            string configFilename            = System.IO.Path.Join(AppContext.BaseDirectory, CONFIG_FILENAME);
            ConfigurationLoader configLoader = new ConfigurationLoader();

            configLoader.LoadFromFile(configFilename);
            _config = configLoader.Configuration;

            //Get list of Music search locations
            List <string> searchLocations = new List <string>();

            searchLocations.Add(System.IO.Path.Join(AppContext.BaseDirectory, "Music"));
            searchLocations.AddRange(_config.SearchLocations);
            _fileLocater = new LocalTrackLocater(searchLocations.ToArray());

            //Instantiate requires classes
            _metadataExtractor           = new MetadataExtractor();
            _localLibraryManager         = new LocalLibraryManager(_fileLocater, _metadataExtractor);
            _musicPlayer                 = new MusicPlayer();
            _queueBuilder                = new QueueBuilder();
            _playlistReader              = new LocalPlaylistReader(_localLibraryManager, System.IO.Path.Join(AppContext.BaseDirectory, "Playlists"));
            _playlistWriter              = new LocalPlaylistWriter(System.IO.Path.Join(AppContext.BaseDirectory, "Playlists"));
            _playlistManager             = new PlaylistManager(_playlistReader, _playlistWriter);
            _trackProgressTimer          = new DispatcherTimer();
            _trackProgressTimer.Interval = TimeSpan.FromSeconds(0.5);
            _trackProgressTimer.Tick    += (_, __) =>
            {
                lblCurrentTime.Content = _musicPlayer.GetCurrentTrackTimePosition().ToString(@"mm\:ss");
            };

            //Initialise the search page
            _searchPage = new TrackPage();


            InitializeComponent();
        }
示例#9
0
        //========================================================================================
        // Constructor
        //========================================================================================

        /// <summary>
        /// Initialize a new instance of this scanner.
        /// </summary>
        /// <param name="controller">The iTunesAppClass to use.</param>
        /// <param name="catalog"></param>
        /// <param name="exportPIDs">
        /// The list of persistent track IDs.  When exporting multiple playlists, this list
        /// should include all tracks from all playlists where each track indicates its own
        /// source playlist.  This allows comprehensive/overall feedback for UI progress bars.
        /// </param>
        /// <param name="encoder">The encoder to use to convert tracks.</param>
        /// <param name="playlistFormat">
        /// The playlist output format or PlaylistProviderFactory.NoFormat for no playlist file.
        /// </param>
        /// <param name="location">
        /// The target root directory path to which all entries will be copied or converted.
        /// </param>
        /// <param name="pathFormat">
        /// The path format string as specified in FolderFormts.xml or null for title only.
        /// </param>
        /// <param name="isSynchronized">
        /// True if target location should be synchronized, removing entries in the target
        /// location that are not included in the exportPIDs collection.
        /// </param>

        public ExportScanner(
            Controller controller, ICatalog catalog, PersistentIDCollection exportPIDs,
            Encoder encoder, string playlistFormat, string location, string pathFormat,
            bool isSynchronized)
            : base(Resx.I_ScanExport, controller, catalog)
        {
            base.description = isSynchronized ? Resx.ScanSynchronize : Resx.ScanExport;
            base.tooltip     = String.Format(Resx.ExportingCount, exportPIDs.Count);

            this.exportPIDs           = exportPIDs;
            this.encoder              = encoder;
            this.expectedType         = (encoder == null ? String.Empty : encoder.ExpectedType);
            this.playlistFormat       = playlistFormat;
            this.playlistName         = exportPIDs.Name;
            this.location             = location;
            this.createSubdirectories = (pathFormat != null);
            this.pathFormat           = pathFormat ?? PathHelper.GetPathFormat(FlatPathFormat);
            this.isSynchronized       = isSynchronized;

            this.exports = null;
            this.writer  = null;
        }
示例#10
0
        /// <summary>
        /// Cleanup anything started in Initialize.
        /// </summary>
        private void Cleanup()
        {
            // detach COM status handlers
            controller.DisabledEvent -= disabledHandler;
            controller.EnabledEvent -= enabledHandler;

            if (saveEncoder != null)
            {
                try
                {
                    // restore the iTunes encoder as specified in the user Preferences
                    controller.CurrentEncoder = saveEncoder;
                }
                catch
                {
                    // no-op
                }
            }

            if (encoder != null)
            {
                encoder.Dispose(true);
                encoder = null;
            }

            if (writer != null)
            {
                writer.Close();
                writer.Dispose();
                writer = null;
            }

            if (exports != null)
            {
                exports.Clear();
                exports = null;
            }

            reset = null;

            base.ProgressPercentage = 100;
            UpdateProgress(Resx.Completed);

            Logger.WriteLine(base.name, "Export completed");
        }
 public void Export(string playlistType, string playlistName, bool excludeSmart, IPlaylistWriter playlistWriter)
 {
     Export(playlistType, new[] { playlistName }, excludeSmart, playlistWriter);
 }
        public void Export(string playlistType, IEnumerable <string> playlistNames, bool excludeSmart, IPlaylistWriter playlistWriter)
        {
            var allPlaylists = GetAllPlaylistsOfType(playlistType, excludeSmart);

            var playlistElements = allPlaylists.Where(xe => playlistNames.Contains(xe.Attribute("title")?.Value)).ToList();

            if (playlistElements.Count <= 0)
            {
                throw new PlaylistExportException($"No playlists of type '{playlistType}' with the specified name(s) were found.");
            }

            foreach (var playlistElement in playlistElements)
            {
                var mediaContainerElement = GetMediaContainer(playlistElement);

                playlistWriter.Write(mediaContainerElement);
            }
        }
示例#13
0
 public void AddWriter(IPlaylistWriter writer)
 {
     Writers.Add(writer.Id, writer);
 }
示例#14
0
 public PlaylistManager(IPlaylistReader PlaylistReader, IPlaylistWriter PlaylistWriter)
 {
     _playlistReader = PlaylistReader;
     _playlistWriter = PlaylistWriter;
 }
 public void AddWriter(IPlaylistWriter writer)
 {
     Writers.Add(writer.Id, writer);
 }
示例#16
0
        /// <summary>
        /// Initialize the environment for an export or synchronize operation.
        /// </summary>
        private void Initialize()
        {
            Logger.WriteLine(base.name,
                String.Format("Export beginning, using encoder '{0}'", encoder.Name));

            // attach COM status handlers
            disabledHandler = new InteractionDisabledHandler(DoCOMCallsDisabled);
            enabledHandler = new InteractionEnabledHandler(DoCOMCallsEnabled);
            controller.DisabledEvent += disabledHandler;
            controller.EnabledEvent += enabledHandler;

            // override current encoder if different than requested
            if (!encoder.IsEmpty)
            {
                if (!controller.CurrentEncoder.Name.Equals(encoder.Name))
                {
                    // remember user's preferred encoder
                    saveEncoder = controller.CurrentEncoder;

                    // set the temporary encoder for this playlist
                    controller.CurrentEncoder = encoder;
                }
            }

            // ensure that 'location' exists before continuing.  This will be more efficient
            // for cases that do not require further subdirectories but also sets the stage...

            if (!Directory.Exists(location))
            {
                if (ScannerBase.isLive)
                {
                    Directory.CreateDirectory(location);
                }
            }

            // if we do want subdirectories then ensure we can create them
            if (!createSubdirectories)
            {
                createSubdirectories = EnsureFolderCapability();
            }

            // initialize and open the playlist writer if a playlist is requested
            if (ScannerBase.isLive && !playlistFormat.Equals(PlaylistFactory.NoFormat))
            {
                writer = PlaylistFactory.CreateWriter(
                    playlistFormat, location, exportPIDs.Name, createSubdirectories);

                writer.Open();
            }

            // this ManualResetEvent is used to synchronize sequential processing of iTunes
            // tracks as they are encoded.  iTunes encoding is an asynchronous procedure
            // however, iTunes does not allow concurrent encodings to occur.

            waitSyncRoot = null;
            reset = new ManualResetEvent(false);
            exports = new StringCollection();
        }
示例#17
0
        private IPlaylistWriter writer; // playlist writer

        #endregion Fields

        #region Constructors

        //========================================================================================
        // Constructor
        //========================================================================================
        /// <summary>
        /// Initialize a new instance of this scanner.
        /// </summary>
        /// <param name="itunes">The iTunesAppClass to use.</param>
        /// <param name="exportPIDs">
        /// The list of persistent track IDs.  When exporting multiple playlists, this list
        /// should include all tracks from all playlists where each track indicates its own
        /// source playlist.  This allows comprehensive/overall feedback for UI progress bars.
        /// </param>
        /// <param name="encoder">The encoder to use to convert tracks.</param>
        /// <param name="playlistFormat">
        /// The playlist output format or PlaylistFactory.NoFormat for no playlist file.
        /// </param>
        /// <param name="location">
        /// The target root directory path to which all entries will be copied or converted.
        /// </param>
        /// <param name="pathFormat">
        /// The path format string as specified in FolderFormts.xml or null for title only.
        /// </param>
        /// <param name="isSynchronized">
        /// True if target location should be synchronized, removing entries in the target
        /// location that are not included in the exportPIDs collection.
        /// </param>
        public ExportScanner(
            Controller controller, PersistentIDCollection exportPIDs,
            Encoder encoder, string playlistFormat, string location, string pathFormat,
            bool isSynchronized)
        {
            base.name = Resx.I_ScanExport;
            base.description = isSynchronized ? Resx.ScanSynchronize : Resx.ScanExport;
            base.controller = controller;

            this.exportPIDs = exportPIDs;
            this.encoder = encoder;
            this.expectedType = encoder.ExpectedType;
            this.playlistFormat = playlistFormat;
            this.playlistName = exportPIDs.Name;
            this.location = location;
            this.createSubdirectories = (pathFormat != null);
            this.pathFormat = pathFormat ?? PathHelper.GetPathFormat(FlatPathFormat);
            this.isSynchronized = isSynchronized;

            this.exports = null;
            this.writer = null;

            this.slim = new ReaderWriterLockSlim();
            this.waitSyncRoot = null;
        }
示例#18
0
 public PlaylistExporterTest()
 {
     _fileSystem     = Substitute.For <IFileSystem>();
     _playlistReader = Substitute.For <IPlaylistReader>();
     _playlistWriter = Substitute.For <IPlaylistWriter>();
 }