scheduling bug fixes (#1238)

This commit is contained in:
Jason Dove
2023-04-11 09:22:51 -05:00
committed by GitHub
parent cf1552910a
commit a684dcced9
9 changed files with 69 additions and 37 deletions
+7
View File
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Fixed
- Limit `HLS Direct` streams to realtime speed
- Fix `Reset Playout` button to use worker thread instead of UI thread
- This fixes potential UI hangs and database concurrency bugs
### Changed
- Remove duplicate items from smart collections before scheduling
- i.e. shows no longer need to be filtered out if search results also include episodes
- Certain multi-collection scenarios may still include duplicates across multiple collections
## [0.7.7-beta] - 2023-04-07
### Added
+30 -4
View File
@@ -4,7 +4,7 @@ using ErsatzTV.Core.Domain;
namespace ErsatzTV.Core.Scheduling;
[DebuggerDisplay("{" + nameof(First) + "}")]
public class GroupedMediaItem
public class GroupedMediaItem : IEquatable<GroupedMediaItem>
{
public GroupedMediaItem()
{
@@ -16,10 +16,36 @@ public class GroupedMediaItem
Additional = additional ?? new List<MediaItem>();
}
public MediaItem First { get; set; }
public List<MediaItem> Additional { get; set; }
public MediaItem First { get; init; }
public List<MediaItem> Additional { get; protected init; }
public static IList<MediaItem> FlattenGroups(GroupedMediaItem[] copy, int mediaItemCount)
public bool Equals(GroupedMediaItem other) =>
Equals(First.Id, other?.First.Id) && Equals(Additional?.Count, other?.Additional?.Count) &&
Equals(Additional?.Map(x => x.Id), other?.Additional?.Map(x => x.Id));
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((GroupedMediaItem)obj);
}
public override int GetHashCode() => HashCode.Combine(First.Id, Additional?.Map(x => x.Id));
public static IList<MediaItem> FlattenGroups(IEnumerable<GroupedMediaItem> copy, int mediaItemCount)
{
var result = new MediaItem[mediaItemCount];
var i = 0;
@@ -11,36 +11,34 @@ public static class MediaItemsForCollection
IArtistRepository artistRepository,
CollectionKey collectionKey)
{
var result = new List<MediaItem>();
switch (collectionKey.CollectionType)
{
case ProgramScheduleItemCollectionType.Collection:
List<MediaItem> collectionItems =
await mediaCollectionRepository.GetItems(collectionKey.CollectionId ?? 0);
return collectionItems;
result.AddRange(await mediaCollectionRepository.GetItems(collectionKey.CollectionId ?? 0));
break;
case ProgramScheduleItemCollectionType.TelevisionShow:
List<Episode> showItems =
await televisionRepository.GetShowItems(collectionKey.MediaItemId ?? 0);
return showItems.Cast<MediaItem>().ToList();
result.AddRange(await televisionRepository.GetShowItems(collectionKey.MediaItemId ?? 0));
break;
case ProgramScheduleItemCollectionType.TelevisionSeason:
List<Episode> seasonItems =
await televisionRepository.GetSeasonItems(collectionKey.MediaItemId ?? 0);
return seasonItems.Cast<MediaItem>().ToList();
result.AddRange(await televisionRepository.GetSeasonItems(collectionKey.MediaItemId ?? 0));
break;
case ProgramScheduleItemCollectionType.Artist:
List<MusicVideo> artistItems =
await artistRepository.GetArtistItems(collectionKey.MediaItemId ?? 0);
return artistItems.Cast<MediaItem>().ToList();
result.AddRange(await artistRepository.GetArtistItems(collectionKey.MediaItemId ?? 0));
break;
case ProgramScheduleItemCollectionType.MultiCollection:
List<MediaItem> multiCollectionItems =
await mediaCollectionRepository.GetMultiCollectionItems(
collectionKey.MultiCollectionId ?? 0);
return multiCollectionItems;
result.AddRange(
await mediaCollectionRepository.GetMultiCollectionItems(collectionKey.MultiCollectionId ?? 0));
break;
case ProgramScheduleItemCollectionType.SmartCollection:
List<MediaItem> smartCollectionItems =
await mediaCollectionRepository.GetSmartCollectionItems(
collectionKey.SmartCollectionId ?? 0);
return smartCollectionItems;
result.AddRange(
await mediaCollectionRepository.GetSmartCollectionItems(collectionKey.SmartCollectionId ?? 0));
break;
default:
return new List<MediaItem>();
}
throw new ArgumentOutOfRangeException();
}
return result.DistinctBy(x => x.Id).ToList();
}
}
@@ -1,8 +1,8 @@
namespace ErsatzTV.Core.Scheduling;
public class MultiCollectionGrouper
public static class MultiCollectionGrouper
{
public static List<GroupedMediaItem> GroupMediaItems(IList<CollectionWithItems> collections)
public static List<GroupedMediaItem> GroupMediaItems(IEnumerable<CollectionWithItems> collections)
{
var result = new List<GroupedMediaItem>();
@@ -18,6 +18,6 @@ public class MultiCollectionGrouper
}
}
return result;
return result.Distinct().ToList();
}
}
@@ -52,7 +52,7 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
State.Seed = _random.Next();
_random = new Random(State.Seed);
_shuffled = Shuffle(_collections, _random);
} while (_collections.Count > 1 && Current == tail);
} while (_collections.Count > 1 && Current.Map(x => x.Id) == tail.Map(x => x.Id));
}
else
{
@@ -49,7 +49,7 @@ public class ShuffledMediaCollectionEnumerator : IMediaCollectionEnumerator
State.Seed = _random.Next();
_random = new CloneableRandom(State.Seed);
_shuffled = Shuffle(_mediaItems, _random);
} while (_mediaItems.Count > 1 && Current == tail);
} while (_mediaItems.Count > 1 && Current.Map(x => x.Id) == tail.Map(x => x.Id));
}
else
{
@@ -86,7 +86,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
}
}
return result.Distinct().ToList();
return result.DistinctBy(x => x.Id).ToList();
}
public async Task<List<MediaItem>> GetSmartCollectionItems(int id)
@@ -150,7 +150,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
result.AddRange(await GetSongItems(dbContext, songIds));
}
return result;
return result.DistinctBy(x => x.Id).ToList();
}
public async Task<List<CollectionWithItems>> GetMultiCollectionCollections(int id)
@@ -221,14 +221,14 @@ public class MediaCollectionRepository : IMediaCollectionRepository
// remove duplicate items from ungrouped collections
var toRemoveFrom = result.Filter(c => !c.ScheduleAsGroup).ToList();
var toRemove = result.Filter(c => c.ScheduleAsGroup)
var scheduleAsGroupItemIds = result.Filter(c => c.ScheduleAsGroup)
.SelectMany(c => c.MediaItems.Map(i => i.Id))
.Distinct()
.ToList();
.ToHashSet();
foreach (CollectionWithItems collection in toRemoveFrom)
{
collection.MediaItems.RemoveAll(mi => toRemove.Contains(mi.Id));
collection.MediaItems.RemoveAll(mi => scheduleAsGroupItemIds.Contains(mi.Id));
}
return result;
@@ -93,7 +93,7 @@ public class MultiEpisodeShuffleCollectionEnumerator : IMediaCollectionEnumerato
State.Seed = _random.Next();
_random = new CloneableRandom(State.Seed);
_shuffled = Shuffle(_random);
} while (_mediaItemCount > 1 && Current == tail);
} while (_mediaItemCount > 1 && Current.Map(x => x.Id) == tail.Map(x => x.Id));
}
else
{
+2 -1
View File
@@ -5,6 +5,7 @@
@implements IDisposable
@inject IDialogService _dialog
@inject IMediator _mediator
@inject ChannelWriter<IBackgroundServiceRequest> WorkerChannel;
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudButton Variant="Variant.Filled" Color="Color.Primary" Link="playouts/add">
@@ -176,7 +177,7 @@
private async Task ResetPlayout(PlayoutNameViewModel playout)
{
await _mediator.Send(new BuildPlayout(playout.PlayoutId, PlayoutBuildMode.Reset), _cts.Token);
await WorkerChannel.WriteAsync(new BuildPlayout(playout.PlayoutId, PlayoutBuildMode.Reset), _cts.Token);
if (_table != null)
{
await _table.ReloadServerData();