private Task DeleteItem(Guid id) { var item = _libraryManager.GetItemById(id); if (item == null) { return(Task.FromResult(true)); } return(_libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false })); }
private void DeleteItem(Guid id) { var item = _libraryManager.GetItemById(id); if (item == null) { return; } _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, false); }
private async Task CleanDeadItems(CancellationToken cancellationToken, IProgress <double> progress) { var itemIds = _libraryManager.GetItemIds(new InternalItemsQuery { HasDeadParentId = true }); var numComplete = 0; var numItems = itemIds.Count; _logger.Debug("Cleaning {0} items with dead parent links", numItems); foreach (var itemId in itemIds) { cancellationToken.ThrowIfCancellationRequested(); var item = _libraryManager.GetItemById(itemId); if (item != null) { _logger.Debug("Cleaning item {0} type: {1} path: {2}", item.Name, item.GetType().Name, item.Path ?? string.Empty); await _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }); } numComplete++; double percent = numComplete; percent /= numItems; progress.Report(percent * 100); } progress.Report(100); }
private void OnLibraryManagerItemUpdated(object?sender, ItemChangeEventArgs itemChangeEventArgs) { // Only interested in real Season and Episode items if (itemChangeEventArgs.Item.IsVirtualItem || !(itemChangeEventArgs.Item is Season || itemChangeEventArgs.Item is Episode)) { return; } if (!IsEnabledForLibrary(itemChangeEventArgs.Item)) { return; } var indexNumber = itemChangeEventArgs.Item.IndexNumber; // If the item is an Episode, filter on ParentIndexNumber as well (season number) int?parentIndexNumber = null; if (itemChangeEventArgs.Item is Episode) { parentIndexNumber = itemChangeEventArgs.Item.ParentIndexNumber; } var query = new InternalItemsQuery { IsVirtualItem = true, IndexNumber = indexNumber, ParentIndexNumber = parentIndexNumber, IncludeItemTypes = new[] { itemChangeEventArgs.Item.GetType().Name }, Parent = itemChangeEventArgs.Parent, GroupByPresentationUniqueKey = false, DtoOptions = new DtoOptions(true) }; var existingVirtualItems = _libraryManager.GetItemList(query); var deleteOptions = new DeleteOptions { DeleteFileLocation = true }; // Remove the virtual season/episode that matches the newly updated item for (var i = 0; i < existingVirtualItems.Count; i++) { _libraryManager.DeleteItem(existingVirtualItems[i], deleteOptions); } }
/// <summary> /// Deletes the specified request. /// </summary> /// <param name="request">The request.</param> public void Delete(DeleteItem request) { var item = _libraryManager.GetItemById(request.Id); var auth = _authContext.GetAuthorizationInfo(Request); var user = _userManager.GetUserById(auth.UserId); if (!item.CanDelete(user)) { throw new UnauthorizedAccessException(); } var task = _libraryManager.DeleteItem(item); Task.WaitAll(task); }
/// <summary> /// Deletes the specified request. /// </summary> /// <param name="request">The request.</param> public void Delete(DeleteItem request) { var item = _libraryManager.GetItemById(request.Id); var auth = _authContext.GetAuthorizationInfo(Request); var user = _userManager.GetUserById(auth.UserId); if (!item.CanDelete(user)) { throw new SecurityException("Unauthorized access"); } if (item is ILiveTvRecording) { var task = _liveTv.DeleteRecording(request.Id); Task.WaitAll(task); } else { var task = _libraryManager.DeleteItem(item); Task.WaitAll(task); } }
/// <summary> /// Removes the virtual entry after a corresponding physical version has been added /// </summary> private async Task <bool> RemoveObsoleteOrMissingEpisodes(IEnumerable <Series> series, IEnumerable <Tuple <int, int> > episodeLookup, bool forceRemoveAll) { var existingEpisodes = (from s in series let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1) from c in s.RecursiveChildren.OfType <Episode>() select new { SeasonOffset = seasonOffset, Episode = c }) .ToList(); var physicalEpisodes = existingEpisodes .Where(i => i.Episode.LocationType != LocationType.Virtual) .ToList(); var virtualEpisodes = existingEpisodes .Where(i => i.Episode.LocationType == LocationType.Virtual) .ToList(); var episodesToRemove = virtualEpisodes .Where(i => { if (forceRemoveAll) { return(true); } if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue) { var seasonNumber = i.Episode.ParentIndexNumber.Value + i.SeasonOffset; var episodeNumber = i.Episode.IndexNumber.Value; // If there's a physical episode with the same season and episode number, delete it if (physicalEpisodes.Any(p => p.Episode.ParentIndexNumber.HasValue && (p.Episode.ParentIndexNumber.Value + p.SeasonOffset) == seasonNumber && p.Episode.ContainsEpisodeNumber(episodeNumber))) { return(true); } // If the episode no longer exists in the remote lookup, delete it if (!episodeLookup.Any(e => e.Item1 == seasonNumber && e.Item2 == episodeNumber)) { return(true); } return(false); } return(true); }) .ToList(); var hasChanges = false; foreach (var episodeToRemove in episodesToRemove.Select(e => e.Episode)) { _logger.Info("Removing missing/unaired episode {0} {1}x{2}", episodeToRemove.Series.Name, episodeToRemove.ParentIndexNumber, episodeToRemove.IndexNumber); await _libraryManager.DeleteItem(episodeToRemove).ConfigureAwait(false); hasChanges = true; } return(hasChanges); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var items = _libraryManager.RootFolder.GetRecursiveChildren(i => i is IHasMusicGenres) .SelectMany(i => i.Genres) .DistinctNames() .ToList(); var numComplete = 0; var count = items.Count; var validIds = new List <Guid>(); foreach (var name in items) { try { var itemByName = _libraryManager.GetMusicGenre(name); validIds.Add(itemByName.Id); await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { // Don't clutter the log break; } catch (Exception ex) { _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; double percent = numComplete; percent /= count; percent *= 100; progress.Report(percent); } var allIds = _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(MusicGenre).Name } }); var invalidIds = allIds .Except(validIds) .ToList(); foreach (var id in invalidIds) { cancellationToken.ThrowIfCancellationRequested(); var item = _libraryManager.GetItemById(id); await _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); } progress.Report(100); }
public async System.Threading.Tasks.Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { if (VersionCheck.IsVersionValid(_appHost.ApplicationVersion, _appHost.SystemUpdateLevel) == false) { _logger.Info("ERROR : Plugin not compatible with this server version"); return; } // query the user playback info for the most active movies ActivityRepository repository = new ActivityRepository(_logger, _config.ApplicationPaths, _fileSystem); ReportPlaybackOptions config = _config.GetReportPlaybackOptions(); foreach (var activity_playlist in config.ActivityPlaylists) { string list_name = activity_playlist.Name; string list_type = activity_playlist.Type; int list_days = activity_playlist.Days; int list_size = activity_playlist.Size; _logger.Info("Activity Playlist - Name:" + list_name + " Type:" + list_type + " Days:" + list_days); string sql = ""; sql += "SELECT ItemId, "; sql += "COUNT(DISTINCT(UserId)) as count, "; sql += "AVG(CAST(strftime('%Y%m%d%H%M', 'now', 'localtime') AS int) - CAST(strftime('%Y%m%d%H%M', DateCreated) AS int)) as av_age "; sql += "FROM PlaybackActivity "; sql += "WHERE ItemType = '" + list_type + "' "; sql += "AND DateCreated > datetime('now', '-" + list_days + " day', 'localtime') "; sql += "GROUP BY ItemId "; sql += "ORDER BY count DESC, av_age ASC "; sql += "LIMIT " + list_size; List <string> cols = new List <string>(); List <List <Object> > query_results = new List <List <object> >(); repository.RunCustomQuery(sql, cols, query_results); List <long> items = new List <long>(); foreach (List <Object> row in query_results) { long item_id = long.Parse((string)row[0]); items.Add(item_id); } // create a playlist with the most active movies string playlist_name = list_name; InternalItemsQuery query = new InternalItemsQuery(); query.IncludeItemTypes = new string[] { "Playlist" }; query.Name = playlist_name; BaseItem[] results = _libraryManager.GetItemList(query, false); foreach (BaseItem item in results) { _logger.Info("Deleting Existing Movie Playlist : " + item.InternalId); DeleteOptions delete_options = new DeleteOptions(); delete_options.DeleteFileLocation = true; _libraryManager.DeleteItem(item, delete_options); } _logger.Info("Creating Movie Playlist"); PlaylistCreationRequest create_options = new PlaylistCreationRequest(); create_options.Name = playlist_name; if (list_type == "Movie") { create_options.MediaType = "Movie"; } else { create_options.MediaType = "Episode"; } create_options.ItemIdList = items.ToArray(); await _playlistman.CreatePlaylist(create_options).ConfigureAwait(false); } }
/// <summary> /// Removes the virtual entry after a corresponding physical version has been added /// </summary> private bool RemoveObsoleteOrMissingEpisodes(Series series, IList <BaseItem> allRecursiveChildren, IEnumerable <Tuple <int, int> > episodeLookup, bool allowMissingEpisodes) { var existingEpisodes = allRecursiveChildren.OfType <Episode>() .ToList(); var physicalEpisodes = existingEpisodes .Where(i => i.LocationType != LocationType.Virtual) .ToList(); var virtualEpisodes = existingEpisodes .Where(i => i.LocationType == LocationType.Virtual) .ToList(); var episodesToRemove = virtualEpisodes .Where(i => { if (i.IndexNumber.HasValue && i.ParentIndexNumber.HasValue) { var seasonNumber = i.ParentIndexNumber.Value; var episodeNumber = i.IndexNumber.Value; // If there's a physical episode with the same season and episode number, delete it if (physicalEpisodes.Any(p => p.ParentIndexNumber.HasValue && (p.ParentIndexNumber.Value) == seasonNumber && p.ContainsEpisodeNumber(episodeNumber))) { return(true); } // If the episode no longer exists in the remote lookup, delete it if (!episodeLookup.Any(e => e.Item1 == seasonNumber && e.Item2 == episodeNumber)) { return(true); } if (!allowMissingEpisodes && i.IsMissingEpisode) { // If it's missing, but not unaired, remove it if (!i.PremiereDate.HasValue || i.PremiereDate.Value.ToLocalTime().Date.AddDays(UnairedEpisodeThresholdDays) < DateTime.Now.Date) { return(true); } } return(false); } return(true); }) .ToList(); var hasChanges = false; foreach (var episodeToRemove in episodesToRemove) { _libraryManager.DeleteItem(episodeToRemove, new DeleteOptions { DeleteFileLocation = true }, false); hasChanges = true; } return(hasChanges); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress <double> progress) { var people = _libraryManager.GetPeopleNames(new InternalPeopleQuery()); var numComplete = 0; var numPeople = people.Count; _logger.LogDebug("Will refresh {0} people", numPeople); foreach (var person in people) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person); var options = new MetadataRefreshOptions(new DirectoryService(_fileSystem)) { ImageRefreshMode = MetadataRefreshMode.ValidationOnly, MetadataRefreshMode = MetadataRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _logger.LogError(ex, "Error validating IBN entry {Person}", person); } // Update progress numComplete++; double percent = numComplete; percent /= numPeople; progress.Report(100 * percent); } var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { BaseItemKind.Person }, IsDeadPerson = true, IsLocked = false }); foreach (var item in deadEntities) { _logger.LogInformation( "Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name); _libraryManager.DeleteItem( item, new DeleteOptions { DeleteFileLocation = false }, false); } progress.Report(100); _logger.LogInformation("People validation complete"); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); var peopleOptions = _config.Configuration.PeopleMetadataOptions; var people = _libraryManager.GetAllPeople(); var dict = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var person in people) { var isMetadataEnabled = DownloadMetadata(person, peopleOptions); bool currentValue; if (dict.TryGetValue(person.Name, out currentValue)) { if (!currentValue && isMetadataEnabled) { dict[person.Name] = true; } } else { dict[person.Name] = isMetadataEnabled; } } var numComplete = 0; var validIds = new List <Guid>(); foreach (var person in dict) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Key); validIds.Add(item.Id); var options = new MetadataRefreshOptions(_fileSystem) { MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly, ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(100 * percent); } var allIds = _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Person).Name } }); var invalidIds = allIds .Except(validIds) .ToList(); foreach (var id in invalidIds) { cancellationToken.ThrowIfCancellationRequested(); var item = _libraryManager.GetItemById(id); if (item != null) { await _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); } } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var names = _itemRepo.GetAllArtistNames(); var numComplete = 0; var count = names.Count; foreach (var name in names) { try { var item = _libraryManager.GetArtist(name); await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { // Don't clutter the log throw; } catch (Exception ex) { _logger.ErrorException("Error refreshing {0}", ex, name); } numComplete++; double percent = numComplete; percent /= count; percent *= 100; progress.Report(percent); } names = names.Select(i => i.RemoveDiacritics()).DistinctNames().ToList(); var artistEntities = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(MusicArtist).Name } }).Cast <MusicArtist>().ToList(); foreach (var artist in artistEntities) { if (!artist.IsAccessedByName) { continue; } var name = (artist.Name ?? string.Empty).RemoveDiacritics(); if (!names.Contains(name, StringComparer.OrdinalIgnoreCase)) { _logger.Info("Deleting dead artist {0} {1}.", artist.Id.ToString("N"), artist.Name); await _libraryManager.DeleteItem(artist, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); } } progress.Report(100); }
public async Task <QueryResult <BaseItem> > GetChannelItemsInternal(InternalItemsQuery query, IProgress <double> progress, CancellationToken cancellationToken) { // Get the internal channel entity var channel = GetChannel(query.ChannelIds[0]); // Find the corresponding channel provider plugin var channelProvider = GetChannelProvider(channel); var user = query.User; ChannelItemSortField?sortField = null; var sortDescending = false; var parentItem = query.ParentId.HasValue ? _libraryManager.GetItemById(query.ParentId.Value) : channel; var itemsResult = await GetChannelItems(channelProvider, user, parentItem is Channel?null : parentItem.ExternalId, sortField, sortDescending, cancellationToken) .ConfigureAwait(false); if (!query.ParentId.HasValue) { query.Parent = channel; } query.ChannelIds = new string[] { }; // Not yet sure why this is causing a problem query.GroupByPresentationUniqueKey = false; //_logger.Debug("GetChannelItemsInternal"); // null if came from cache if (itemsResult != null) { var internalItems = itemsResult.Items .Select(i => GetChannelItemEntity(i, channelProvider, channel.Id, parentItem.Id, cancellationToken)) .ToArray(); var existingIds = _libraryManager.GetItemIds(query); var deadIds = existingIds.Except(internalItems.Select(i => i.Id)) .ToArray(); foreach (var deadId in deadIds) { var deadItem = _libraryManager.GetItemById(deadId); if (deadItem != null) { _libraryManager.DeleteItem(deadItem, new DeleteOptions { DeleteFileLocation = false, DeleteFromExternalProvider = false }, parentItem, false); } } } return(_libraryManager.GetItemsResult(query)); }
private Task DeleteItem(DeleteItem request) { var item = _dtoService.GetItemByDtoId(request.Id); return(_libraryManager.DeleteItem(item)); }