Example #1
0
        public async Task Search()
        {
            SearchResults.Clear();
            var status = LibraryStatus;

            if (status == null)
            {
                //Debug.WriteLine("Searching: " + Term);
                // Search cancellation is not directly supported. Instead, when a search is complete, before updating the search results we ensure that the search
                // term has not changed. If the search term has changed meanwhile, it means we've received out-of-date data, in which case it is ignored.
                var searchTerm = Term;
                var results    = await WebAwareT(async() => {
                    return(await MusicProvider.Search(Term));
                });

                // WebAwareT returns default(T) if there's an exception
                var isResultUpToDate = searchTerm == Term;
                if (results != null && isResultUpToDate)
                {
                    foreach (var result in results)
                    {
                        SearchResults.Add(result);
                    }
                    if (results.Count() == 0)
                    {
                        FeedbackMessage = "No results for: " + Term;
                    }
                }
            }
            else
            {
                FeedbackMessage = status;
            }
        }
Example #2
0
 public MusicDialog()
 {
     _musicProviders.Add(new YandexMusic());
     _mainMusicProvider              = _musicProviders[0];
     AssistantCore.Assistant.Mute   += TechnicalMute;
     AssistantCore.Assistant.Unmute += TechnicalUnmute;
 }
Example #3
0
        /// <summary>
        /// Checks the configured library locations for new/updated/deleted files,
        /// and updates the database accordingly
        /// </summary>
        private async Task SynchroniseDb()
        {
            await Console.Out.WriteLineAsync("LibraryMonitor: Starting update (enumerating files).");

            using (var mp = new MusicProvider())
            {
                var lastDBUpdateTime = mp.GetLastUpdateTime();
                // Set the last update time now
                // Otherwise, files that change between now and update completion
                // might not get flagged for update up in the next sync round
                await mp.SetLastUpdateTime(DateTime.UtcNow.ToUniversalTime());

                foreach (var libraryLocation in m_libraryLocations)
                {
                    await FindFilesToUpdate(libraryLocation, mp, lastDBUpdateTime);
                }
            }

            await Console.Out.WriteLineAsync($"LibraryMonitor: {m_filesToUpdate.Count} files need to be updated and {m_filesToAdd.Count} files need to be added.");

            await UpdateFiles();

            m_filesToUpdate.Clear();
            await AddNewFiles();

            m_filesToAdd.Clear();
            await DeleteStaleDbEntries();

            await Console.Out.WriteLineAsync("LibraryMonitor: Database update completed successfully.");

            // Schedule the next sync
            m_syncTimer.Change(SYNC_INTERVAL_SECONDS * 1000, Timeout.Infinite);
        }
Example #4
0
        public static WebViewWrapper WrapperFactory(MusicProvider provider)
        {
            WKUserContentController controller = new WKUserContentController();

            controller.AddUserScript(
                new WKUserScript(new NSString(provider.EventsJs), WKUserScriptInjectionTime.AtDocumentEnd, false)
                );
            controller.AddScriptMessageHandler(Container.WKScriptMessageHandler, "playbackState");

            WKWebViewConfiguration config = new WKWebViewConfiguration
            {
                UserContentController = controller
            };

            config.Preferences.SetValueForKey(NSObject.FromObject(true), new NSString("developerExtrasEnabled"));

            var webView = new WKWebView(new CGRect(0, 0, 100, 100), config)
            {
                CustomUserAgent = "Mozilla/5.0 " +
                                  "(Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 " +
                                  "(KHTML, like Gecko) Version/12.0 Safari/605.1.15",
                AutoresizingMask   = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable,
                NavigationDelegate = new NavigationDelegate()
            };

            webView.TranslatesAutoresizingMaskIntoConstraints = false;
            var req = new NSUrlRequest(new NSUrl(provider.Url));

            webView.LoadRequest(req);

            return(new WebViewWrapper(webView, provider));
        }
Example #5
0
        /// <summary>
        /// Keeps the download progress properties of the music items up-to-date
        /// so that the progress can be displayed under each item in the UI.
        ///
        /// The music items in the library and the playlist do not point to the
        /// same object even if it's the same track so we need to update both places separately.
        /// </summary>
        /// <param name="transfer"></param>
        protected override void OnDownloadStatusUpdate(BackgroundTransferRequest transfer)
        {
            base.OnDownloadStatusUpdate(transfer);
            var path          = FileUtilsBase.UnixSeparators(transfer.Tag.Substring(PhoneLocalLibrary.Instance.BaseMusicPath.Length));
            var musicItem     = MusicProvider.SearchItem(path);
            var isDownloading = transfer.TransferStatus == TransferStatus.Transferring;
            var bytesReceived = (ulong)transfer.BytesReceived;

            // updates track in the library
            if (musicItem != null)
            {
                MusicItem.SetDownloadStatus(musicItem, bytesReceived);
                musicItem.IsDownloading = isDownloading;
            }
            // updates the track in the playlist
            var playlistTracks = PimpViewModel.Instance.MusicPlayer.Playlist.Songs
                                 .Where(item => item.Song.Path == path)
                                 .ToList(); // beautiful!!!

            BasePlaylist.SetDownloadStatus(playlistTracks, bytesReceived);
            foreach (var item in playlistTracks)
            {
                item.Song.IsDownloading = isDownloading;
            }
        }
Example #6
0
 /// <summary>
 /// Recursively adds all files in @param startDirectory (of the configured file types)
 /// that have been created or modified since @lastDBUpdateTime
 /// to the list of files that need to be updated in/added to the database
 /// </summary>
 /// <param name="startDirectory">Where to start looking for new/updated files</param>
 /// <param name="mp">Handle to the database</param>
 /// <param name="lastDBUpdateTime">Write time beyond which files will be condsidered new or modified</param>
 /// <returns></returns>
 private async Task FindFilesToUpdate(
     string startDirectory,
     MusicProvider mp,
     DateTime lastDBUpdateTime
     )
 {
     foreach (var subDir in Directory.EnumerateDirectories(startDirectory))
     {
         if (new DirectoryInfo(subDir).LastWriteTime > lastDBUpdateTime)
         {
             await FindFilesToUpdate(subDir, mp, lastDBUpdateTime);
         }
     }
     foreach (var filePattern in m_filePatterns)
     {
         foreach (var file in Directory.EnumerateFiles(startDirectory, filePattern, SearchOption.TopDirectoryOnly))
         {
             if (!(await mp.AllTracks.AsNoTracking().AnyAsync(t => t.FileName == file)))
             {
                 m_filesToAdd.Add(file);
             }
             else if (new FileInfo(file).LastWriteTime.ToUniversalTime() > lastDBUpdateTime)
             {
                 m_filesToUpdate.Add(file);
             }
         }
     }
 }
Example #7
0
        /// <summary>
        /// Adds all new files marked for addition to the database
        /// Clears files marked for addition
        /// </summary>
        private async Task AddNewFiles()
        {
            if (m_filesToAdd.Count() < 1)
            {
                return;
            }

            foreach (var slice in m_filesToAdd.GetSlices(SAVE_TO_DISK_INTERVAL))
            {
                var newTracks = new List <DbTrack>();
                foreach (var trackFileName in slice)
                {
                    var newTrack = new DbTrack {
                        FileName = trackFileName
                    };
                    newTrack.SetTrackData(TagLib.File.Create(trackFileName).Tag);
                    newTracks.Add(newTrack);
                }
                using (MusicProvider mp = new MusicProvider())
                {
                    await mp.AllTracks.AddRangeAsync(newTracks);

                    await mp.SaveChangesAsync();
                }
            }
        }
Example #8
0
        public static WebViewWrapper BuildWebViewWrapper(MusicProvider musicProvider)
        {
            WebView webView = new WebView();

            webView.Navigate(new Uri(musicProvider.Url));
            return(new WebViewWrapper(webView, musicProvider));
        }
Example #9
0
        public static List <MediaSessionCompat.QueueItem> GetRandomQueue(MusicProvider musicProvider)
        {
            var shuffled = musicProvider.GetShuffledMusic();
            var result   = shuffled.Take(RandomQueueSize).ToList();

            LogHelper.Debug(Tag, "getRandomQueue: result.size=", result.Count);

            return(ConvertToQueue(result, "random"));
        }
Example #10
0
        public async Task <bool> AddTemp(OnlinePlaylist playlist)
        {
            if (playlist.Entries == null || playlist.Entries.Count == 0)
            {
                playlist.Entries = await GetOnlineTracks(playlist);
            }

            return(await MusicProvider.AddTemp(playlist));
        }
Example #11
0
        public async Task DownloadFolder(MusicItem folder)
        {
            var tracks = await MusicProvider.SongsInFolder(folder);

            foreach (var t in tracks)
            {
                await SubmitDownload(t);
            }
        }
Example #12
0
        private async Task SubmitFolder(MusicItem folder)
        {
            var tracks = await MusicProvider.SongsInFolder(folder);

            foreach (var item in tracks)
            {
                await SubmitDownload(item);
            }
        }
        private void HandleClick(MusicProvider provider)
        {
            if (provider == currentProvider)
            {
                return;
            }

            currentProvider = provider;
            RaiseProviderClicked(provider);
        }
Example #14
0
        public Platform(Jint.Engine engine, MusicProvider musicProvider, ISettingsService settingsService, IMvxNavigationService mvxNavigationService, IAuthenticationService authenticationService, IMvxLogProvider logProvider)
        {
            _engine        = engine;
            _musicProvider = musicProvider;

            _settingsService       = settingsService;
            _mvxNavigationService  = mvxNavigationService;
            _authenticationService = authenticationService;
            _logProvider           = logProvider;
        }
Example #15
0
        public async Task ReSync()
        {
            using (new Spinner(Strings.SyncingDatabase)) {
                var apis  = Collection.Values.ToList();
                var tasks = apis.Select(x => x.Resync());
                await Task.WhenAll(tasks);

                await MusicProvider.SetOffline();
            }
        }
Example #16
0
        public QueueManager(MusicProvider musicProvider,
                            Resources resources,
                            MetadataUpdateListener listener)
        {
            this.musicProvider = musicProvider;
            this.listener      = listener;
            this.resources     = resources;

            playingQueue = new SynchronizedList <MediaSessionCompat.QueueItem>();
            currentIndex = 0;
        }
Example #17
0
 public WebViewWrapperBase GetWebViewWrapper(MusicProvider provider)
 {
     webViewWrappers = webViewWrappers ?? new Dictionary <string, WebViewWrapperBase>();
     if (!webViewWrappers.ContainsKey(provider.Id))
     {
         WebViewWrapperBase wrapper = wrapperFactory(provider);
         wrapper.PlayerStateChanged  += Wrapper_PlayerStateChanged;
         wrapper.NowPlayingChanged   += Wrapper_NowPlayingChanged;
         webViewWrappers[provider.Id] = wrapper;
     }
     return(webViewWrappers[provider.Id]);
 }
Example #18
0
        protected async void Refresh_Click(object sender, EventArgs e)
        {
            var wasUpdated = await EndpointScanner.Instance.SyncIfUnreachable(libraryManager.ActiveEndpoint);

            if (!wasUpdated)
            {
                // If the endpoint was updated, Reset is called anyway by PimpViewModel.
                // This ensures it's called exactly once.
                MusicProvider.Reset();
            }
            //await OnMusicItemsNavigatedTo();
            await LoadMusicItems();
        }
Example #19
0
 public async Task <List <MusicItem> > GetSongsRecursively(MusicItem songOrDir)
 {
     if (!songOrDir.IsDir)
     {
         var tracks = new List <MusicItem>();
         tracks.Add(songOrDir);
         return(tracks);
     }
     else
     {
         return(await MusicProvider.SongsInFolder(songOrDir));
     }
 }
Example #20
0
        public async Task TrackDownloaded(string trackId)
        {
            var track = Database.Main.GetObject <Track, TempTrack> (trackId);

            if (track == null)
            {
                return;
            }

            var filePath = Path.Combine(Locations.MusicDir, track.FileName);
            var song     = Database.Main.GetObject <Song, TempSong> (track.SongId);

            try {
                using (var file = TagLib.File.Create(filePath)) {
                    file.Tag.Title      = song.Name;
                    file.Tag.Album      = song.Album;
                    file.Tag.Performers = file.Tag.AlbumArtists = new string[] { song.Artist };
                    file.Tag.Disc       = (uint)song.Disc;
                    file.Tag.Track      = (uint)song.Track;
                    file.Tag.TrackCount = (uint)song.TrackCount;
                    file.Tag.Year       = (uint)song.Year;
                    file.Tag.Genres     = new string[] { song.Genre };
                    //var artwork = await getARtwork(song);
                    //if (!string.IsNullOrWhiteSpace(artwork))
                    //file.Tag.Pictures = new TagLib.IPicture[] {new TagLib.Picture(artwork) };
                    file.Save();
                    //if (File.Exists(artwork))
                    //File.Delete(artwork);
                }
            } catch (Exception ex) {
                LogManager.Shared.Report(ex);
            }

            var newTrack = new Track {
                Id            = track.FileName,
                Duration      = track.Duration,
                Genre         = track.Genre,
                SongId        = track.SongId,
                ServiceType   = ServiceType.FileSystem,
                AlbumId       = track.AlbumId,
                ArtistId      = track.ArtistId,
                Deleted       = false,
                ServiceId     = track.ServiceId,
                MediaType     = track.MediaType,
                FileExtension = track.FileExtension,
            };

            //File.Move(filePath, Path.Combine(Locations.MusicDir, CleanFileName($"{song.Artist} - {song.Name}.mp3")));
            Database.Main.InsertOrReplace(newTrack);
            await MusicProvider.SetOffline(newTrack);
        }
Example #21
0
        public async Task <string> Load()
        {
            await WebAware(async() => {
                MusicProvider.NewItemsLoaded += MusicProvider_NewItemsLoaded;
                try {
                    await MusicProvider.LoadFolder(FolderId, MusicItems);
                } finally {
                    MusicProvider.NewItemsLoaded -= MusicProvider_NewItemsLoaded;
                }
            });

            FeedbackMessage = DetermineFeedbackMessage();
            return(FeedbackMessage);
        }
Example #22
0
        public WebViewWrapper(object webView, MusicProvider musicProvider) : base(webView, musicProvider)
        {
            InitWebView();

            if (musicProvider.Id == "Saavn")
            {
                return;
            }

            timer          = new DispatcherTimer();
            timer.Tick    += Timer_Tick;
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Start();
        }
Example #23
0
        async void ToggleIPod(bool on)
        {
            Settings.IncludeIpod = on;
            var ipod = ApiManager.Shared.GetMusicProvider <iPodProvider>(ServiceType.iPod);

            if (on)
            {
                ipod.SyncDatabase();
            }
            else
            {
                MusicProvider.RemoveApi(ipod.Id);
            }
        }
Example #24
0
        public async Task LogOut(MusicProvider provider)
        {
            try {
                await provider.Logout();

                int id;
                if (int.TryParse(provider.Id, out id))
                {
                    Settings.DeleteApiModel(id);
                }
                Collection.Remove(provider.Id);
            } catch (Exception ex) {
                Console.WriteLine(ex);
            }
        }
Example #25
0
		async Task StartDownload (Song song)
		{
			if(song == null)
				return;
			var track = await MusicManager.Shared.GetTrack (song.Id);
			if (track == null) {
				LogManager.Shared.Report (new Exception ("Track is null...."));
				return;
			}
			if (track.ServiceType == ServiceType.iPod || track.ServiceType == ServiceType.FileSystem) {
				await MusicProvider.SetOffline (track);
				return;
			}
			await BackgroundDownloadManager.Shared.Download (track);
		}
Example #26
0
        async Task <bool> SyncLibrary(string href = "")
        {
            try
            {
                var resp = await SyncRequestQueue.Enqueue(1, () => string.IsNullOrWhiteSpace(href)?Api.GetFavorites() : Api.Get <SApiResponse <STrack> >(href)).ConfigureAwait(false);

                Task <bool> nextTask = null;
                if (!string.IsNullOrWhiteSpace(resp?.NextUrl))
                {
                    nextTask = SyncLibrary(resp?.NextUrl);
                }

                var tracks = resp?.Items.Select(x => new FullTrackData(x.Title, x.User?.Username, "", "", x.Genre)
                {
                    Id             = x.Id.ToString(),
                    Duration       = x.Duration,
                    ArtistServerId = x.UserId.ToString(),
                    MediaType      = MediaType.Audio,
                    PlayCount      = x.UserPlaybackCount ?? 0,
                    ServiceId      = Api.CurrentAccount.Identifier,
                    ServiceType    = this.ServiceType,
                    FileExtension  = "mp3",
                    Rating         = 5,
                    Year           = x.ReleaseYear ?? 0,
                    AlbumArtwork   = new List <AlbumArtwork> {
                        new AlbumArtwork {
                            Url = x.ArtworkUrl
                        }
                    },
                }).ToList();
                if ((tracks?.Count ?? 0) == 0)
                {
                    return(true);
                }
                await MusicProvider.ProcessTracks(tracks);

                if (nextTask != null)
                {
                    return(await nextTask);
                }
                return(true);
            }
            catch (Exception ex)
            {
                LogManager.Shared.Report(ex);
            }
            return(false);
        }
        private void RenderProvider(MusicProvider provider)
        {
            var rightView = rightController.View;

            if (rightView.Subviews.Length > 0)
            {
                rightView.Subviews[0].RemoveFromSuperview();
            }
            WKWebView webView = (WKWebView)viewModel.GetWebViewWrapper(provider).WebView;

            rightView.AddSubview(webView);

            webView.TopAnchor.ConstraintEqualToAnchor(rightView.TopAnchor).Active       = true;
            webView.BottomAnchor.ConstraintEqualToAnchor(rightView.BottomAnchor).Active = true;
            webView.LeftAnchor.ConstraintEqualToAnchor(rightView.LeftAnchor).Active     = true;
            webView.RightAnchor.ConstraintEqualToAnchor(rightView.RightAnchor).Active   = true;
        }
Example #28
0
        /// <summary>
        /// Downloads the song in the background if it's not already available offline.
        /// </summary>
        /// <param name="track"></param>
        public async Task SubmitDownload(MusicItem track)
        {
            await BeforeDownload(track);

            try {
                var maybeLocalUri = await PhoneLocalLibrary.Instance.LocalUriIfExists(track);

                if (maybeLocalUri == null)
                {
                    // For Subsonic, the response may be transcoded audio, in which case the
                    // path to the track, which has the original file extension as stored on
                    // the server, may be incorrect (example: response is transcoded to .mp3,
                    // path is .flac).

                    // TODO: Ensure that the file is stored locally with the correct extension,
                    // that is, find out whether the response is transcoded.
                    var destination = LocalLibrary.AbsolutePathTo(track);
                    var downloadUri = MusicProvider.DownloadUriFor(track);
                    // Only downloads tracks that are stored as MP3s, because this app does not support other local file formats.
                    if (destination.EndsWith("mp3"))
                    {
                        var downloadable = new Downloadable(downloadUri, destination);
                        if (LoadTransfersCount() < 3)
                        {
                            AddTransfer(downloadUri, destination);
                        }
                        else
                        {
                            // add the download to persistent storage from which it will be taken
                            // later when there are fewer concurrent downloads
                            DownloadDataContext.Add(downloadable);
                        }
                    }
                }
            } catch (PathTooLongException) {
                // Thrown if track.Path is about over 190 characters long, but I'm not sure what
                // the limit is and I don't want to be too defensive with this so I catch and
                // suppress the exception when it occurs.

                // The exception says "The specified path, file name, or both are too long.
                // The fully qualified file name must be less than 260 characters, and the
                // directory name must be less than 248 characters.", however, I don't know
                // the length of the fully qualified path name, so 190 chars is an estimate.
                AddMessage("Download of " + track.Name + " failed. The path is too long: " + track.Path);
            }
        }
Example #29
0
        protected override void OnDownloadStatusUpdate(DownloadOperation download)
        {
            base.OnDownloadStatusUpdate(download);
            // Updates the BytesReceived property of the possibly loaded MusicItem
            // so that a progress bar may be displayed under the item
            var musicPath     = AppLocalFolderLibrary.MusicPath(download.ResultFile);
            var musicItem     = MusicProvider.SearchItem(musicPath);
            var progress      = download.Progress;
            var bytesReceived = progress.BytesReceived;

            if (musicItem != null)
            {
                MusicItem.SetDownloadStatus(musicItem, bytesReceived);
            }
            var playlistTracks = Playlist.Songs.Where(item => item.Song.Path == musicPath).ToList();

            BasePlaylist.SetDownloadStatus(playlistTracks, bytesReceived);
        }
Example #30
0
        async Task <bool> GetTracks(string continuation = "")
        {
            try
            {
                var resp = await SyncRequestQueue.Enqueue(1, () => Api.GetSpecialFolderDelta("music", token: continuation)).ConfigureAwait(false);

                Task <bool> nextTask = null;
                if (!string.IsNullOrWhiteSpace(resp?.DeltaToken) && !string.IsNullOrWhiteSpace(resp?.NextLink))
                {
                    nextTask = GetTracks(resp?.DeltaToken);
                }

                var tracks = resp?.Value.Where(x => x.Audio != null).Select(x => new FullTrackData(x.Audio.Title, x.Audio.Artist, x.Audio.Artist, x.Audio.Album, x.Audio.Genre)
                {
                    Id             = x.Id,
                    Duration       = x.Audio.Duration,
                    ArtistServerId = x.Audio.Artist,
                    MediaType      = MediaType.Audio,
                    PlayCount      = 0,
                    ServiceId      = Api.CurrentAccount.Identifier,
                    ServiceType    = this.ServiceType,
                    FileExtension  = System.IO.Path.GetExtension(x.Name),
                    Rating         = 5,
                    Year           = x.Audio.Year,
                }).ToList();
                if ((tracks?.Count ?? 0) == 0)
                {
                    return(true);
                }
                await MusicProvider.ProcessTracks(tracks);

                if (nextTask != null)
                {
                    return(await nextTask);
                }
                Api.ExtraData.LastSongSync = resp.DeltaToken;
                return(true);
            }
            catch (Exception ex)
            {
                LogManager.Shared.Report(ex);
            }
            return(false);
        }