Merge pull request #9 from jellyfin/master

Yanking in latest changes
This commit is contained in:
LogicalPhallacy 2019-02-11 22:48:50 -08:00 committed by GitHub
commit 8bf88f4cb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
349 changed files with 2446 additions and 4839 deletions

View file

@ -15,6 +15,7 @@
- [cvium](https://github.com/cvium)
- [wtayl0r](https://github.com/wtayl0r)
- [TtheCreator](https://github.com/Tthecreator)
- [dkanada](https://github.com/dkanada)
- [LogicalPhallacy](https://github.com/LogicalPhallacy/)
- [RazeLighter777](https://github.com/RazeLighter777)

View file

@ -10,7 +10,7 @@ RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
--output /jellyfin \
Jellyfin.Server
FROM jrottenberg/ffmpeg:4.0-scratch as ffmpeg
FROM jrottenberg/ffmpeg:4.0-vaapi as ffmpeg
FROM microsoft/dotnet:${DOTNET_VERSION}-runtime
# libfontconfig1 is required for Skia
RUN apt-get update \
@ -23,4 +23,4 @@ COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config

View file

@ -21,4 +21,4 @@ RUN apt-get update \
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config

View file

@ -30,4 +30,4 @@ COPY --from=qemu_extract qemu-* /usr/bin
COPY --from=builder /jellyfin /jellyfin
EXPOSE 8096
VOLUME /config /media
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config

View file

@ -236,7 +236,9 @@ namespace Emby.Dlna.Api
public object Get(GetIcon request)
{
var contentType = "image/" + Path.GetExtension(request.Filename).TrimStart('.').ToLower();
var contentType = "image/" + Path.GetExtension(request.Filename)
.TrimStart('.')
.ToLowerInvariant();
var cacheLength = TimeSpan.FromDays(365);
var cacheKey = Request.RawUrl.GetMD5();

View file

@ -63,7 +63,7 @@ namespace Emby.Dlna.ContentDirectory
_profile = profile;
_config = config;
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, libraryManager, mediaEncoder);
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, mediaEncoder);
}
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
@ -454,7 +454,7 @@ namespace Emby.Dlna.ContentDirectory
User = user,
Recursive = true,
IsMissing = false,
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
ExcludeItemTypes = new[] { typeof(Book).Name },
IsFolder = isFolder,
MediaTypes = mediaTypes.ToArray(),
DtoOptions = GetDtoOptions()
@ -523,7 +523,7 @@ namespace Emby.Dlna.ContentDirectory
Limit = limit,
StartIndex = startIndex,
IsVirtualItem = false,
ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
ExcludeItemTypes = new[] { typeof(Book).Name },
IsPlaceHolder = false,
DtoOptions = GetDtoOptions()
};

View file

@ -43,22 +43,30 @@ namespace Emby.Dlna.Didl
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly IMediaEncoder _mediaEncoder;
public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
public DidlBuilder(
DeviceProfile profile,
User user,
IImageProcessor imageProcessor,
string serverAddress,
string accessToken,
IUserDataManager userDataManager,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
ILogger logger,
IMediaEncoder mediaEncoder)
{
_profile = profile;
_user = user;
_imageProcessor = imageProcessor;
_serverAddress = serverAddress;
_accessToken = accessToken;
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_logger = logger;
_libraryManager = libraryManager;
_mediaEncoder = mediaEncoder;
_accessToken = accessToken;
_user = user;
}
public static string NormalizeDlnaMediaUrl(string url)
@ -117,7 +125,8 @@ namespace Emby.Dlna.Didl
}
}
public void WriteItemElement(DlnaOptions options,
public void WriteItemElement(
DlnaOptions options,
XmlWriter writer,
BaseItem item,
User user,
@ -232,12 +241,15 @@ namespace Emby.Dlna.Didl
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
}
var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken)
.Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
.ToList();
var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken);
foreach (var subtitle in subtitleProfiles)
{
if (subtitle.DeliveryMethod != SubtitleDeliveryMethod.External)
{
continue;
}
var subtitleAdded = AddSubtitleElement(writer, subtitle);
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
@ -250,7 +262,8 @@ namespace Emby.Dlna.Didl
private bool AddSubtitleElement(XmlWriter writer, SubtitleStreamInfo info)
{
var subtitleProfile = _profile.SubtitleProfiles
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External);
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase)
&& i.Method == SubtitleDeliveryMethod.External);
if (subtitleProfile == null)
{
@ -265,7 +278,7 @@ namespace Emby.Dlna.Didl
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
writer.WriteStartElement("sec", "CaptionInfoEx", null);
writer.WriteAttributeString("sec", "type", null, info.Format.ToLower());
writer.WriteAttributeString("sec", "type", null, info.Format.ToLowerInvariant());
writer.WriteString(info.Url);
writer.WriteFullEndElement();
@ -282,7 +295,7 @@ namespace Emby.Dlna.Didl
else
{
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLower());
var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant());
writer.WriteAttributeString("protocolInfo", protocolInfo);
writer.WriteString(info.Url);
@ -387,91 +400,39 @@ namespace Emby.Dlna.Didl
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
{
if (itemStubType.HasValue && itemStubType.Value == StubType.Latest)
if (itemStubType.HasValue)
{
return _localization.GetLocalizedString("Latest");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Playlists)
{
return _localization.GetLocalizedString("Playlists");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.AlbumArtists)
{
return _localization.GetLocalizedString("HeaderAlbumArtists");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Albums)
{
return _localization.GetLocalizedString("Albums");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Artists)
{
return _localization.GetLocalizedString("Artists");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Songs)
{
return _localization.GetLocalizedString("Songs");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Genres)
{
return _localization.GetLocalizedString("Genres");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteAlbums)
{
return _localization.GetLocalizedString("HeaderFavoriteAlbums");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteArtists)
{
return _localization.GetLocalizedString("HeaderFavoriteArtists");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSongs)
{
return _localization.GetLocalizedString("HeaderFavoriteSongs");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.ContinueWatching)
{
return _localization.GetLocalizedString("HeaderContinueWatching");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Movies)
{
return _localization.GetLocalizedString("Movies");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Collections)
{
return _localization.GetLocalizedString("Collections");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Favorites)
{
return _localization.GetLocalizedString("Favorites");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.NextUp)
{
return _localization.GetLocalizedString("HeaderNextUp");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteSeries)
{
return _localization.GetLocalizedString("HeaderFavoriteShows");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.FavoriteEpisodes)
{
return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Series)
{
return _localization.GetLocalizedString("Shows");
switch (itemStubType.Value)
{
case StubType.Latest: return _localization.GetLocalizedString("Latest");
case StubType.Playlists: return _localization.GetLocalizedString("Playlists");
case StubType.AlbumArtists: return _localization.GetLocalizedString("HeaderAlbumArtists");
case StubType.Albums: return _localization.GetLocalizedString("Albums");
case StubType.Artists: return _localization.GetLocalizedString("Artists");
case StubType.Songs: return _localization.GetLocalizedString("Songs");
case StubType.Genres: return _localization.GetLocalizedString("Genres");
case StubType.FavoriteAlbums: return _localization.GetLocalizedString("HeaderFavoriteAlbums");
case StubType.FavoriteArtists: return _localization.GetLocalizedString("HeaderFavoriteArtists");
case StubType.FavoriteSongs: return _localization.GetLocalizedString("HeaderFavoriteSongs");
case StubType.ContinueWatching: return _localization.GetLocalizedString("HeaderContinueWatching");
case StubType.Movies: return _localization.GetLocalizedString("Movies");
case StubType.Collections: return _localization.GetLocalizedString("Collections");
case StubType.Favorites: return _localization.GetLocalizedString("Favorites");
case StubType.NextUp: return _localization.GetLocalizedString("HeaderNextUp");
case StubType.FavoriteSeries: return _localization.GetLocalizedString("HeaderFavoriteShows");
case StubType.FavoriteEpisodes: return _localization.GetLocalizedString("HeaderFavoriteEpisodes");
case StubType.Series: return _localization.GetLocalizedString("Shows");
default: break;
}
}
var episode = item as Episode;
var season = context as Season;
if (episode != null && season != null)
if (item is Episode episode && context is Season season)
{
// This is a special embedded within a season
if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0)
if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0
&& season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
{
if (season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
{
return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
}
return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
}
if (item.IndexNumber.HasValue)
@ -585,10 +546,8 @@ namespace Emby.Dlna.Didl
public static bool IsIdRoot(string id)
{
if (string.IsNullOrWhiteSpace(id) ||
string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
if (string.IsNullOrWhiteSpace(id)
|| string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
// Samsung sometimes uses 1 as root
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
{
@ -808,7 +767,7 @@ namespace Emby.Dlna.Didl
{
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre");
}
else if (item is Genre || item is GameGenre)
else if (item is Genre)
{
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre");
}
@ -844,7 +803,7 @@ namespace Emby.Dlna.Didl
// var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
// ?? PersonType.Actor;
// AddValue(writer, "upnp", type.ToLower(), actor.Name, NS_UPNP);
// AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
// index++;
@ -1112,7 +1071,7 @@ namespace Emby.Dlna.Didl
};
}
class ImageDownloadInfo
private class ImageDownloadInfo
{
internal Guid ItemId;
internal string ImageTag;
@ -1128,7 +1087,7 @@ namespace Emby.Dlna.Didl
internal ItemImageInfo ItemImageInfo;
}
class ImageUrlInfo
private class ImageUrlInfo
{
internal string Url;
@ -1147,7 +1106,7 @@ namespace Emby.Dlna.Didl
if (stubType.HasValue)
{
id = stubType.Value.ToString().ToLower() + "_" + id;
id = stubType.Value.ToString().ToLowerInvariant() + "_" + id;
}
return id;

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Emby.Dlna.Profiles;
using Emby.Dlna.Server;
using MediaBrowser.Common.Configuration;
@ -48,11 +49,11 @@ namespace Emby.Dlna
_assemblyInfo = assemblyInfo;
}
public void InitProfiles()
public async Task InitProfilesAsync()
{
try
{
ExtractSystemProfiles();
await ExtractSystemProfilesAsync();
LoadProfiles();
}
catch (Exception ex)
@ -300,7 +301,7 @@ namespace Emby.Dlna
profile = ReserializeProfile(tempProfile);
profile.Id = path.ToLower().GetMD5().ToString("N");
profile.Id = path.ToLowerInvariant().GetMD5().ToString("N");
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
@ -352,14 +353,14 @@ namespace Emby.Dlna
Info = new DeviceProfileInfo
{
Id = file.FullName.ToLower().GetMD5().ToString("N"),
Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N"),
Name = _fileSystem.GetFileNameWithoutExtension(file),
Type = type
}
};
}
private void ExtractSystemProfiles()
private async Task ExtractSystemProfilesAsync()
{
var namespaceName = GetType().Namespace + ".Profiles.Xml.";
@ -383,7 +384,7 @@ namespace Emby.Dlna
using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
{
stream.CopyTo(fileStream);
await stream.CopyToAsync(fileStream);
}
}
}
@ -506,7 +507,7 @@ namespace Emby.Dlna
? ImageFormat.Png
: ImageFormat.Jpg;
var resource = GetType().Namespace + ".Images." + filename.ToLower();
var resource = GetType().Namespace + ".Images." + filename.ToLowerInvariant();
return new ImageStream
{

View file

@ -20,7 +20,6 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
using Rssdp;
@ -49,8 +48,7 @@ namespace Emby.Dlna.Main
private readonly IDeviceDiscovery _deviceDiscovery;
private SsdpDevicePublisher _Publisher;
private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory;
private readonly IEnvironmentInfo _environmentInfo;
private readonly INetworkManager _networkManager;
@ -78,7 +76,6 @@ namespace Emby.Dlna.Main
IDeviceDiscovery deviceDiscovery,
IMediaEncoder mediaEncoder,
ISocketFactory socketFactory,
ITimerFactory timerFactory,
IEnvironmentInfo environmentInfo,
INetworkManager networkManager,
IUserViewManager userViewManager,
@ -99,7 +96,6 @@ namespace Emby.Dlna.Main
_deviceDiscovery = deviceDiscovery;
_mediaEncoder = mediaEncoder;
_socketFactory = socketFactory;
_timerFactory = timerFactory;
_environmentInfo = environmentInfo;
_networkManager = networkManager;
_logger = loggerFactory.CreateLogger("Dlna");
@ -125,9 +121,9 @@ namespace Emby.Dlna.Main
Current = this;
}
public void Run()
public async Task RunAsync()
{
((DlnaManager)_dlnaManager).InitProfiles();
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
ReloadComponents();
@ -233,7 +229,7 @@ namespace Emby.Dlna.Main
try
{
_Publisher = new SsdpDevicePublisher(_communicationsServer, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
_Publisher = new SsdpDevicePublisher(_communicationsServer, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
_Publisher.LogFunction = LogMessage;
_Publisher.SupportPnpRootDevice = false;
@ -263,7 +259,7 @@ namespace Emby.Dlna.Main
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address.ToString());
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
var descriptorUri = "/dlna/" + udn + "/description.xml";
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
@ -353,8 +349,7 @@ namespace Emby.Dlna.Main
_userDataManager,
_localization,
_mediaSourceManager,
_mediaEncoder,
_timerFactory);
_mediaEncoder);
_manager.Start();
}

View file

@ -10,7 +10,6 @@ using Emby.Dlna.Server;
using Emby.Dlna.Ssdp;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
@ -19,7 +18,7 @@ namespace Emby.Dlna.PlayTo
{
#region Fields & Properties
private ITimer _timer;
private Timer _timer;
public DeviceInfo Properties { get; set; }
@ -40,12 +39,7 @@ namespace Emby.Dlna.PlayTo
public TimeSpan? Duration { get; set; }
private TimeSpan _position = TimeSpan.FromSeconds(0);
public TimeSpan Position
{
get => _position;
set => _position = value;
}
public TimeSpan Position { get; set; } = TimeSpan.FromSeconds(0);
public TRANSPORTSTATE TransportState { get; private set; }
@ -61,24 +55,20 @@ namespace Emby.Dlna.PlayTo
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
public DateTime DateLastActivity { get; private set; }
public Action OnDeviceUnavailable { get; set; }
private readonly ITimerFactory _timerFactory;
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config, ITimerFactory timerFactory)
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config)
{
Properties = deviceProperties;
_httpClient = httpClient;
_logger = logger;
_config = config;
_timerFactory = timerFactory;
}
public void Start()
{
_logger.LogDebug("Dlna Device.Start");
_timer = _timerFactory.Create(TimerCallback, null, 1000, Timeout.Infinite);
_timer = new Timer(TimerCallback, null, 1000, Timeout.Infinite);
}
private DateTime _lastVolumeRefresh;
@ -119,7 +109,9 @@ namespace Emby.Dlna.PlayTo
lock (_timerLock)
{
if (_disposed)
{
return;
}
_volumeRefreshActive = true;
@ -136,7 +128,9 @@ namespace Emby.Dlna.PlayTo
lock (_timerLock)
{
if (_disposed)
{
return;
}
_volumeRefreshActive = false;
@ -144,11 +138,6 @@ namespace Emby.Dlna.PlayTo
}
}
public void OnPlaybackStartedExternally()
{
RestartTimer(true);
}
#region Commanding
public Task VolumeDown(CancellationToken cancellationToken)
@ -333,7 +322,9 @@ namespace Emby.Dlna.PlayTo
private string CreateDidlMeta(string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
return DescriptionXmlBuilder.Escape(value);
}
@ -342,10 +333,11 @@ namespace Emby.Dlna.PlayTo
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Play");
if (command == null)
{
return Task.CompletedTask;
}
var service = GetAvTransportService();
if (service == null)
{
throw new InvalidOperationException("Unable to find service");
@ -369,7 +361,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Stop");
if (command == null)
{
return;
}
var service = GetAvTransportService();
@ -385,7 +379,9 @@ namespace Emby.Dlna.PlayTo
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "Pause");
if (command == null)
{
return;
}
var service = GetAvTransportService();
@ -405,7 +401,9 @@ namespace Emby.Dlna.PlayTo
private async void TimerCallback(object sender)
{
if (_disposed)
{
return;
}
try
{
@ -425,8 +423,6 @@ namespace Emby.Dlna.PlayTo
return;
}
DateLastActivity = DateTime.UtcNow;
if (transportState.HasValue)
{
// If we're not playing anything no need to get additional data
@ -505,7 +501,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetVolume");
if (command == null)
{
return;
}
var service = GetServiceRenderingControl();
@ -518,13 +516,17 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
{
return;
}
var volume = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetVolumeResponse").Select(i => i.Element("CurrentVolume")).FirstOrDefault(i => i != null);
var volumeValue = volume == null ? null : volume.Value;
var volumeValue = volume?.Value;
if (string.IsNullOrWhiteSpace(volumeValue))
{
return;
}
Volume = int.Parse(volumeValue, UsCulture);
@ -545,7 +547,9 @@ namespace Emby.Dlna.PlayTo
var command = rendererCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMute");
if (command == null)
{
return;
}
var service = GetServiceRenderingControl();
@ -560,39 +564,44 @@ namespace Emby.Dlna.PlayTo
if (result == null || result.Document == null)
return;
var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse").Select(i => i.Element("CurrentMute")).FirstOrDefault(i => i != null);
var value = valueNode == null ? null : valueNode.Value;
var valueNode = result.Document.Descendants(uPnpNamespaces.RenderingControl + "GetMuteResponse")
.Select(i => i.Element("CurrentMute"))
.FirstOrDefault(i => i != null);
IsMuted = string.Equals(value, "1", StringComparison.OrdinalIgnoreCase);
IsMuted = string.Equals(valueNode?.Value, "1", StringComparison.OrdinalIgnoreCase);
}
private async Task<TRANSPORTSTATE?> GetTransportInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetTransportInfo");
if (command == null)
{
return null;
}
var service = GetAvTransportService();
if (service == null)
{
return null;
}
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
.ConfigureAwait(false);
if (result == null || result.Document == null)
{
return null;
}
var transportState =
result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
var transportStateValue = transportState == null ? null : transportState.Value;
if (transportStateValue != null)
if (transportStateValue != null
&& Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
{
if (Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))
{
return state;
}
return state;
}
return null;
@ -602,10 +611,11 @@ namespace Emby.Dlna.PlayTo
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
if (command == null)
{
return null;
}
var service = GetAvTransportService();
if (service == null)
{
throw new InvalidOperationException("Unable to find service");
@ -617,7 +627,9 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
{
return null;
}
var track = result.Document.Descendants("CurrentURIMetaData").FirstOrDefault();
@ -657,11 +669,13 @@ namespace Emby.Dlna.PlayTo
return null;
}
private async Task<Tuple<bool, uBaseObject>> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
private async Task<(bool, uBaseObject)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command == null)
return new Tuple<bool, uBaseObject>(false, null);
{
return (false, null);
}
var service = GetAvTransportService();
@ -676,7 +690,9 @@ namespace Emby.Dlna.PlayTo
.ConfigureAwait(false);
if (result == null || result.Document == null)
return new Tuple<bool, uBaseObject>(false, null);
{
return (false, null);
}
var trackUriElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackURI")).FirstOrDefault(i => i != null);
var trackUri = trackUriElem == null ? null : trackUriElem.Value;
@ -684,8 +700,8 @@ namespace Emby.Dlna.PlayTo
var durationElem = result.Document.Descendants(uPnpNamespaces.AvTransport + "GetPositionInfoResponse").Select(i => i.Element("TrackDuration")).FirstOrDefault(i => i != null);
var duration = durationElem == null ? null : durationElem.Value;
if (!string.IsNullOrWhiteSpace(duration) &&
!string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
if (!string.IsNullOrWhiteSpace(duration)
&& !string.Equals(duration, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
Duration = TimeSpan.Parse(duration, UsCulture);
}
@ -707,14 +723,14 @@ namespace Emby.Dlna.PlayTo
if (track == null)
{
//If track is null, some vendors do this, use GetMediaInfo instead
return new Tuple<bool, uBaseObject>(true, null);
return (true, null);
}
var trackString = (string)track;
if (string.IsNullOrWhiteSpace(trackString) || string.Equals(trackString, "NOT_IMPLEMENTED", StringComparison.OrdinalIgnoreCase))
{
return new Tuple<bool, uBaseObject>(true, null);
return (true, null);
}
XElement uPnpResponse;
@ -735,7 +751,7 @@ namespace Emby.Dlna.PlayTo
catch (Exception ex)
{
_logger.LogError(ex, "Unable to parse xml {0}", trackString);
return new Tuple<bool, uBaseObject>(true, null);
return (true, null);
}
}
@ -743,7 +759,7 @@ namespace Emby.Dlna.PlayTo
var uTrack = CreateUBaseObject(e, trackUri);
return new Tuple<bool, uBaseObject>(true, uTrack);
return (true, uTrack);
}
private static uBaseObject CreateUBaseObject(XElement container, string trackUri)
@ -801,11 +817,9 @@ namespace Emby.Dlna.PlayTo
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
{
var avCommands = AvCommands;
if (avCommands != null)
if (AvCommands != null)
{
return avCommands;
return AvCommands;
}
if (_disposed)
@ -825,18 +839,15 @@ namespace Emby.Dlna.PlayTo
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
avCommands = TransportCommands.Create(document);
AvCommands = avCommands;
return avCommands;
AvCommands = TransportCommands.Create(document);
return AvCommands;
}
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
{
var rendererCommands = RendererCommands;
if (rendererCommands != null)
if (RendererCommands != null)
{
return rendererCommands;
return RendererCommands;
}
if (_disposed)
@ -845,7 +856,6 @@ namespace Emby.Dlna.PlayTo
}
var avService = GetServiceRenderingControl();
if (avService == null)
{
throw new ArgumentException("Device AvService is null");
@ -857,9 +867,8 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
rendererCommands = TransportCommands.Create(document);
RendererCommands = rendererCommands;
return rendererCommands;
RendererCommands = TransportCommands.Create(document);
return RendererCommands;
}
private string NormalizeUrl(string baseUrl, string url)
@ -871,85 +880,103 @@ namespace Emby.Dlna.PlayTo
}
if (!url.Contains("/"))
{
url = "/dmr/" + url;
}
if (!url.StartsWith("/"))
{
url = "/" + url;
}
return baseUrl + url;
}
private TransportCommands AvCommands
{
get;
set;
}
private TransportCommands AvCommands { get; set; }
private TransportCommands RendererCommands
{
get;
set;
}
private TransportCommands RendererCommands { get; set; }
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory, CancellationToken cancellationToken)
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
{
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
var deviceProperties = new DeviceInfo();
var friendlyNames = new List<string>();
var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault();
if (name != null && !string.IsNullOrWhiteSpace(name.Value))
{
friendlyNames.Add(name.Value);
}
var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault();
if (room != null && !string.IsNullOrWhiteSpace(room.Value))
{
friendlyNames.Add(room.Value);
}
deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
var deviceProperties = new DeviceInfo()
{
Name = string.Join(" ", friendlyNames),
BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port)
};
var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
if (model != null)
{
deviceProperties.ModelName = model.Value;
}
var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault();
if (modelNumber != null)
{
deviceProperties.ModelNumber = modelNumber.Value;
}
var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault();
if (uuid != null)
{
deviceProperties.UUID = uuid.Value;
}
var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault();
if (manufacturer != null)
{
deviceProperties.Manufacturer = manufacturer.Value;
}
var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault();
if (manufacturerUrl != null)
{
deviceProperties.ManufacturerUrl = manufacturerUrl.Value;
}
var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault();
if (presentationUrl != null)
{
deviceProperties.PresentationUrl = presentationUrl.Value;
}
var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault();
if (modelUrl != null)
{
deviceProperties.ModelUrl = modelUrl.Value;
}
var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault();
if (serialNumber != null)
{
deviceProperties.SerialNumber = serialNumber.Value;
}
var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault();
if (modelDescription != null)
{
deviceProperties.ModelDescription = modelDescription.Value;
deviceProperties.BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port);
}
var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault();
if (icon != null)
{
deviceProperties.Icon = CreateIcon(icon);
@ -958,12 +985,15 @@ namespace Emby.Dlna.PlayTo
foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList")))
{
if (services == null)
{
continue;
}
var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service"));
if (servicesList == null)
{
continue;
}
foreach (var element in servicesList)
{
@ -976,9 +1006,7 @@ namespace Emby.Dlna.PlayTo
}
}
var device = new Device(deviceProperties, httpClient, logger, config, timerFactory);
return device;
return new Device(deviceProperties, httpClient, logger, config);
}
#endregion
@ -1065,13 +1093,10 @@ namespace Emby.Dlna.PlayTo
private void OnPlaybackStart(uBaseObject mediaInfo)
{
if (PlaybackStart != null)
PlaybackStart?.Invoke(this, new PlaybackStartEventArgs
{
PlaybackStart.Invoke(this, new PlaybackStartEventArgs
{
MediaInfo = mediaInfo
});
}
MediaInfo = mediaInfo
});
}
private void OnPlaybackProgress(uBaseObject mediaInfo)
@ -1082,58 +1107,56 @@ namespace Emby.Dlna.PlayTo
return;
}
if (PlaybackProgress != null)
PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs
{
PlaybackProgress.Invoke(this, new PlaybackProgressEventArgs
{
MediaInfo = mediaInfo
});
}
MediaInfo = mediaInfo
});
}
private void OnPlaybackStop(uBaseObject mediaInfo)
{
if (PlaybackStopped != null)
PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs
{
PlaybackStopped.Invoke(this, new PlaybackStoppedEventArgs
{
MediaInfo = mediaInfo
});
}
MediaInfo = mediaInfo
});
}
private void OnMediaChanged(uBaseObject old, uBaseObject newMedia)
{
if (MediaChanged != null)
MediaChanged?.Invoke(this, new MediaChangedEventArgs
{
MediaChanged.Invoke(this, new MediaChangedEventArgs
{
OldMediaInfo = old,
NewMediaInfo = newMedia
});
}
OldMediaInfo = old,
NewMediaInfo = newMedia
});
}
#region IDisposable
bool _disposed;
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
DisposeTimer();
}
Dispose(true);
GC.SuppressFinalize(this);
}
private void DisposeTimer()
protected virtual void Dispose(bool disposing)
{
if (_timer != null)
if (_disposed)
{
_timer.Dispose();
_timer = null;
return;
}
if (disposing)
{
_timer?.Dispose();
}
_timer = null;
Properties = null;
_disposed = true;
}
#endregion

View file

@ -42,30 +42,43 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
private readonly string _accessToken;
private readonly DateTime _creationTime;
public bool IsSessionActive => !_disposed && _device != null;
public bool SupportsMediaControl => IsSessionActive;
public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder)
public PlayToController(
SessionInfo session,
ISessionManager sessionManager,
ILibraryManager libraryManager,
ILogger logger,
IDlnaManager dlnaManager,
IUserManager userManager,
IImageProcessor imageProcessor,
string serverAddress,
string accessToken,
IDeviceDiscovery deviceDiscovery,
IUserDataManager userDataManager,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
IConfigurationManager config,
IMediaEncoder mediaEncoder)
{
_session = session;
_sessionManager = sessionManager;
_libraryManager = libraryManager;
_logger = logger;
_dlnaManager = dlnaManager;
_userManager = userManager;
_imageProcessor = imageProcessor;
_serverAddress = serverAddress;
_accessToken = accessToken;
_deviceDiscovery = deviceDiscovery;
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_config = config;
_mediaEncoder = mediaEncoder;
_accessToken = accessToken;
_logger = logger;
_creationTime = DateTime.UtcNow;
}
public void Init(Device device)
@ -374,9 +387,7 @@ namespace Emby.Dlna.PlayTo
return _device.IsPaused ? _device.SetPlay(CancellationToken.None) : _device.SetPause(CancellationToken.None);
case PlaystateCommand.Seek:
{
return Seek(command.SeekPositionTicks ?? 0);
}
return Seek(command.SeekPositionTicks ?? 0);
case PlaystateCommand.NextTrack:
return SetPlaylistIndex(_currentPlaylistIndex + 1);
@ -442,8 +453,7 @@ namespace Emby.Dlna.PlayTo
var profile = _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
var hasMediaSources = item as IHasMediaSources;
var mediaSources = hasMediaSources != null
var mediaSources = item is IHasMediaSources
? (_mediaSourceManager.GetStaticMediaSources(item, true, user))
: new List<MediaSourceInfo>();
@ -452,7 +462,7 @@ namespace Emby.Dlna.PlayTo
playlistItem.StreamUrl = DidlBuilder.NormalizeDlnaMediaUrl(playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken));
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder)
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _mediaEncoder)
.GetItemDidl(_config.GetDlnaConfiguration(), item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
playlistItem.Didl = itemXml;

View file

@ -16,7 +16,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Dlna.PlayTo
@ -39,13 +38,12 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly ITimerFactory _timerFactory;
private bool _disposed;
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory)
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@ -61,7 +59,6 @@ namespace Emby.Dlna.PlayTo
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_mediaEncoder = mediaEncoder;
_timerFactory = timerFactory;
}
public void Start()
@ -168,7 +165,7 @@ namespace Emby.Dlna.PlayTo
if (controller == null)
{
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory, cancellationToken).ConfigureAwait(false);
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, cancellationToken).ConfigureAwait(false);
string deviceName = device.Properties.Name;

View file

@ -107,19 +107,19 @@ namespace Emby.Dlna.Server
'&'
};
private static readonly string[] s_escapeStringPairs = new string[]
{
"<",
"&lt;",
">",
"&gt;",
"\"",
"&quot;",
"'",
"&apos;",
"&",
"&amp;"
};
private static readonly string[] s_escapeStringPairs = new[]
{
"<",
"&lt;",
">",
"&gt;",
"\"",
"&quot;",
"'",
"&apos;",
"&",
"&amp;"
};
private static string GetEscapeSequence(char c)
{
@ -133,7 +133,7 @@ namespace Emby.Dlna.Server
return result;
}
}
return c.ToString();
return c.ToString(CultureInfo.InvariantCulture);
}
/// <summary>Replaces invalid XML characters in a string with their valid XML equivalent.</summary>
@ -145,6 +145,7 @@ namespace Emby.Dlna.Server
{
return null;
}
StringBuilder stringBuilder = null;
int length = str.Length;
int num = 0;
@ -230,9 +231,9 @@ namespace Emby.Dlna.Server
var serverName = new string(characters);
var name = (_profile.FriendlyName ?? string.Empty).Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase);
var name = _profile.FriendlyName?.Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase);
return name;
return name ?? string.Empty;
}
private void AppendIconList(StringBuilder builder)
@ -295,65 +296,62 @@ namespace Emby.Dlna.Server
}
private IEnumerable<DeviceIcon> GetIcons()
{
var list = new List<DeviceIcon>();
list.Add(new DeviceIcon
=> new[]
{
MimeType = "image/png",
Depth = "24",
Width = 240,
Height = 240,
Url = "icons/logo240.png"
});
new DeviceIcon
{
MimeType = "image/png",
Depth = "24",
Width = 240,
Height = 240,
Url = "icons/logo240.png"
},
list.Add(new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 240,
Height = 240,
Url = "icons/logo240.jpg"
});
new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 240,
Height = 240,
Url = "icons/logo240.jpg"
},
list.Add(new DeviceIcon
{
MimeType = "image/png",
Depth = "24",
Width = 120,
Height = 120,
Url = "icons/logo120.png"
});
new DeviceIcon
{
MimeType = "image/png",
Depth = "24",
Width = 120,
Height = 120,
Url = "icons/logo120.png"
},
list.Add(new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 120,
Height = 120,
Url = "icons/logo120.jpg"
});
new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 120,
Height = 120,
Url = "icons/logo120.jpg"
},
list.Add(new DeviceIcon
{
MimeType = "image/png",
Depth = "24",
Width = 48,
Height = 48,
Url = "icons/logo48.png"
});
new DeviceIcon
{
MimeType = "image/png",
Depth = "24",
Width = 48,
Height = 48,
Url = "icons/logo48.png"
},
list.Add(new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 48,
Height = 48,
Url = "icons/logo48.jpg"
});
return list;
}
new DeviceIcon
{
MimeType = "image/jpeg",
Depth = "24",
Width = 48,
Height = 48,
Url = "icons/logo48.jpg"
}
};
private IEnumerable<DeviceService> GetServices()
{

View file

@ -5,7 +5,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
using Rssdp;
using Rssdp.Infrastructure;
@ -48,20 +47,17 @@ namespace Emby.Dlna.Ssdp
private SsdpDeviceLocator _deviceLocator;
private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory;
private ISsdpCommunicationsServer _commsServer;
public DeviceDiscovery(
ILoggerFactory loggerFactory,
IServerConfigurationManager config,
ISocketFactory socketFactory,
ITimerFactory timerFactory)
ISocketFactory socketFactory)
{
_logger = loggerFactory.CreateLogger(nameof(DeviceDiscovery));
_config = config;
_socketFactory = socketFactory;
_timerFactory = timerFactory;
}
// Call this method from somewhere in your code to start the search.
@ -78,7 +74,7 @@ namespace Emby.Dlna.Ssdp
{
if (_listenerCount > 0 && _deviceLocator == null)
{
_deviceLocator = new SsdpDeviceLocator(_commsServer, _timerFactory);
_deviceLocator = new SsdpDeviceLocator(_commsServer);
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the

View file

@ -83,8 +83,8 @@ namespace Emby.Drawing
}
}
public string[] SupportedInputFormats =>
new string[]
public IReadOnlyCollection<string> SupportedInputFormats =>
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"tiff",
"tif",
@ -137,14 +137,14 @@ namespace Emby.Drawing
}
}
public ImageFormat[] GetSupportedImageOutputFormats()
{
return _imageEncoder.SupportedOutputFormats;
}
public IReadOnlyCollection<ImageFormat> GetSupportedImageOutputFormats()
=> _imageEncoder.SupportedOutputFormats;
private static readonly HashSet<string> TransparentImageTypes
= new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
private static readonly string[] TransparentImageTypes = new string[] { ".png", ".webp", ".gif" };
public bool SupportsTransparency(string path)
=> TransparentImageTypes.Contains(Path.GetExtension(path).ToLower());
=> TransparentImageTypes.Contains(Path.GetExtension(path));
public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options)
{
@ -261,15 +261,6 @@ namespace Emby.Drawing
return (cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
}
catch (ArgumentOutOfRangeException ex)
{
// Decoder failed to decode it
#if DEBUG
_logger.LogError(ex, "Error encoding image");
#endif
// Just spit out the original file if all the options are default
return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
catch (Exception ex)
{
// If it fails for whatever reason, return the original image
@ -374,13 +365,13 @@ namespace Emby.Drawing
filename += "v=" + Version;
return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLowerInvariant());
}
public ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info)
=> GetImageSize(item, info, true);
public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info)
=> GetImageDimensions(item, info, true);
public ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info, bool updateItem)
public ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem)
{
int width = info.Width;
int height = info.Height;
@ -393,7 +384,7 @@ namespace Emby.Drawing
string path = info.Path;
_logger.LogInformation("Getting image size for item {ItemType} {Path}", item.GetType().Name, path);
ImageDimensions size = GetImageSize(path);
ImageDimensions size = GetImageDimensions(path);
info.Width = size.Width;
info.Height = size.Height;
@ -408,7 +399,7 @@ namespace Emby.Drawing
/// <summary>
/// Gets the size of the image.
/// </summary>
public ImageDimensions GetImageSize(string path)
public ImageDimensions GetImageDimensions(string path)
=> _imageEncoder.GetImageSize(path);
/// <summary>
@ -481,7 +472,7 @@ namespace Emby.Drawing
return (originalImagePath, dateModified);
}
if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat, StringComparer.OrdinalIgnoreCase))
if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat))
{
try
{

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Drawing;
@ -6,15 +7,11 @@ namespace Emby.Drawing
{
public class NullImageEncoder : IImageEncoder
{
public string[] SupportedInputFormats =>
new[]
{
"png",
"jpeg",
"jpg"
};
public IReadOnlyCollection<string> SupportedInputFormats
=> new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "png", "jpeg", "jpg" };
public ImageFormat[] SupportedOutputFormats => new[] { ImageFormat.Jpg, ImageFormat.Png };
public IReadOnlyCollection<ImageFormat> SupportedOutputFormats
=> new HashSet<ImageFormat>() { ImageFormat.Jpg, ImageFormat.Png };
public void CropWhiteSpace(string inputPath, string outputPath)
{

View file

@ -121,7 +121,7 @@ namespace IsoMounter
path,
Path.GetExtension(path),
EnvironmentInfo.OperatingSystem,
ExecutablesAvailable.ToString()
ExecutablesAvailable
);
if (ExecutablesAvailable)
@ -183,7 +183,7 @@ namespace IsoMounter
_logger.LogInformation(
"[{0}] Disposing [{1}].",
Name,
disposing.ToString()
disposing
);
if (disposing)
@ -229,9 +229,8 @@ namespace IsoMounter
var uid = getuid();
_logger.LogDebug(
"[{0}] Our current UID is [{1}], GetUserId() returned [{2}].",
"[{0}] GetUserId() returned [{2}].",
Name,
uid.ToString(),
uid
);

View file

@ -73,11 +73,6 @@ namespace Emby.Notifications
Type = NotificationType.AudioPlayback.ToString()
},
new NotificationTypeInfo
{
Type = NotificationType.GamePlayback.ToString()
},
new NotificationTypeInfo
{
Type = NotificationType.VideoPlayback.ToString()
@ -88,11 +83,6 @@ namespace Emby.Notifications
Type = NotificationType.AudioPlaybackStopped.ToString()
},
new NotificationTypeInfo
{
Type = NotificationType.GamePlaybackStopped.ToString()
},
new NotificationTypeInfo
{
Type = NotificationType.VideoPlaybackStopped.ToString()

View file

@ -20,7 +20,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Notifications;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Notifications
@ -40,9 +39,8 @@ namespace Emby.Notifications
private readonly ILibraryManager _libraryManager;
private readonly ISessionManager _sessionManager;
private readonly IServerApplicationHost _appHost;
private readonly ITimerFactory _timerFactory;
private ITimer LibraryUpdateTimer { get; set; }
private Timer LibraryUpdateTimer { get; set; }
private readonly object _libraryChangedSyncLock = new object();
private readonly IConfigurationManager _config;
@ -52,7 +50,7 @@ namespace Emby.Notifications
private string[] _coreNotificationTypes;
public Notifications(IInstallationManager installationManager, IActivityManager activityManager, ILocalizationManager localization, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost, IConfigurationManager config, IDeviceManager deviceManager, ITimerFactory timerFactory)
public Notifications(IInstallationManager installationManager, IActivityManager activityManager, ILocalizationManager localization, IUserManager userManager, ILogger logger, ITaskManager taskManager, INotificationManager notificationManager, ILibraryManager libraryManager, ISessionManager sessionManager, IServerApplicationHost appHost, IConfigurationManager config, IDeviceManager deviceManager)
{
_installationManager = installationManager;
_userManager = userManager;
@ -64,19 +62,20 @@ namespace Emby.Notifications
_appHost = appHost;
_config = config;
_deviceManager = deviceManager;
_timerFactory = timerFactory;
_localization = localization;
_activityManager = activityManager;
_coreNotificationTypes = new CoreNotificationTypes(localization, appHost).GetNotificationTypes().Select(i => i.Type).ToArray();
}
public void Run()
public Task RunAsync()
{
_libraryManager.ItemAdded += _libraryManager_ItemAdded;
_appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
_appHost.HasUpdateAvailableChanged += _appHost_HasUpdateAvailableChanged;
_activityManager.EntryCreated += _activityManager_EntryCreated;
return Task.CompletedTask;
}
private async void _appHost_HasPendingRestartChanged(object sender, EventArgs e)
@ -157,7 +156,7 @@ namespace Emby.Notifications
{
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, 5000,
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, 5000,
Timeout.Infinite);
}
else

View file

@ -181,7 +181,7 @@ namespace Emby.Photos
try
{
var size = _imageProcessor.GetImageSize(item, img, false);
var size = _imageProcessor.GetImageDimensions(item, img, false);
if (size.Width > 0 && size.Height > 0)
{

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
@ -58,7 +59,7 @@ namespace Emby.Server.Implementations.Activity
_deviceManager = deviceManager;
}
public void Run()
public Task RunAsync()
{
_taskManager.TaskCompleted += _taskManager_TaskCompleted;
@ -90,6 +91,8 @@ namespace Emby.Server.Implementations.Activity
_deviceManager.CameraImageUploaded += _deviceManager_CameraImageUploaded;
_appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
return Task.CompletedTask;
}
void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
@ -207,10 +210,6 @@ namespace Emby.Server.Implementations.Activity
{
return NotificationType.AudioPlayback.ToString();
}
if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.GamePlayback.ToString();
}
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.VideoPlayback.ToString();
@ -225,10 +224,6 @@ namespace Emby.Server.Implementations.Activity
{
return NotificationType.AudioPlaybackStopped.ToString();
}
if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.GamePlaybackStopped.ToString();
}
if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
{
return NotificationType.VideoPlaybackStopped.ToString();

View file

@ -16,12 +16,14 @@ namespace Emby.Server.Implementations.AppBase
string programDataPath,
string appFolderPath,
string logDirectoryPath = null,
string configurationDirectoryPath = null)
string configurationDirectoryPath = null,
string cacheDirectoryPath = null)
{
ProgramDataPath = programDataPath;
ProgramSystemPath = appFolderPath;
LogDirectoryPath = logDirectoryPath;
ConfigurationDirectoryPath = configurationDirectoryPath;
CachePath = cacheDirectoryPath;
}
public string ProgramDataPath { get; private set; }

View file

@ -171,16 +171,29 @@ namespace Emby.Server.Implementations.AppBase
private void UpdateCachePath()
{
string cachePath;
// If the configuration file has no entry (i.e. not set in UI)
if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
{
cachePath = null;
// If the current live configuration has no entry (i.e. not set on CLI/envvars, during startup)
if (string.IsNullOrWhiteSpace(((BaseApplicationPaths)CommonApplicationPaths).CachePath))
{
// Set cachePath to a default value under ProgramDataPath
cachePath = Path.Combine(((BaseApplicationPaths)CommonApplicationPaths).ProgramDataPath, "cache");
}
else
{
// Set cachePath to the existing live value; will require restart if UI value is removed (but not replaced)
// TODO: Figure out how to re-grab this from the CLI/envvars while running
cachePath = ((BaseApplicationPaths)CommonApplicationPaths).CachePath;
}
}
else
{
cachePath = Path.Combine(CommonConfiguration.CachePath, "cache");
// Set cachePath to the new UI-set value
cachePath = CommonConfiguration.CachePath;
}
Logger.LogInformation("Setting cache path to " + cachePath);
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
}
@ -217,7 +230,7 @@ namespace Emby.Server.Implementations.AppBase
private string GetConfigurationFile(string key)
{
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLowerInvariant() + ".xml");
}
public object GetConfiguration(string key)

View file

@ -12,7 +12,6 @@ using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Common.Implementations.Serialization;
using Emby.Dlna;
using Emby.Dlna.Main;
using Emby.Dlna.Ssdp;
@ -43,7 +42,6 @@ using Emby.Server.Implementations.ScheduledTasks;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.Threading;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using Emby.Server.Implementations.Xml;
@ -99,7 +97,6 @@ using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Updates;
using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Chapters;
@ -110,7 +107,6 @@ using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.Extensions.Logging;
using ServiceStack;
using ServiceStack.Text.Jsv;
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
namespace Emby.Server.Implementations
@ -141,7 +137,7 @@ namespace Emby.Server.Implementations
return false;
}
if (StartupOptions.ContainsOption("-service"))
if (StartupOptions.IsService)
{
return false;
}
@ -302,7 +298,7 @@ namespace Emby.Server.Implementations
private ILiveTvManager LiveTvManager { get; set; }
public ILocalizationManager LocalizationManager { get; set; }
public LocalizationManager LocalizationManager { get; set; }
private IEncodingManager EncodingManager { get; set; }
private IChannelManager ChannelManager { get; set; }
@ -343,12 +339,11 @@ namespace Emby.Server.Implementations
protected IHttpResultFactory HttpResultFactory { get; private set; }
protected IAuthService AuthService { get; private set; }
public StartupOptions StartupOptions { get; private set; }
public IStartupOptions StartupOptions { get; private set; }
internal IImageEncoder ImageEncoder { get; private set; }
protected IProcessFactory ProcessFactory { get; private set; }
protected ITimerFactory TimerFactory { get; private set; }
protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
protected readonly IXmlSerializer XmlSerializer;
@ -364,7 +359,7 @@ namespace Emby.Server.Implementations
/// </summary>
public ApplicationHost(ServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
StartupOptions options,
IStartupOptions options,
IFileSystem fileSystem,
IEnvironmentInfo environmentInfo,
IImageEncoder imageEncoder,
@ -646,8 +641,10 @@ namespace Emby.Server.Implementations
/// <summary>
/// Runs the startup tasks.
/// </summary>
public Task RunStartupTasks()
public async Task RunStartupTasks()
{
Logger.LogInformation("Running startup tasks");
Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
@ -666,20 +663,20 @@ namespace Emby.Server.Implementations
Logger.LogInformation("ServerId: {0}", SystemId);
var entryPoints = GetExports<IServerEntryPoint>();
RunEntryPoints(entryPoints, true);
var now = DateTime.UtcNow;
await Task.WhenAll(StartEntryPoints(entryPoints, true));
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
Logger.LogInformation("Core startup complete");
HttpServer.GlobalResponse = null;
Logger.LogInformation("Post-init migrations complete");
RunEntryPoints(entryPoints, false);
Logger.LogInformation("All entry points have started");
return Task.CompletedTask;
now = DateTime.UtcNow;
await Task.WhenAll(StartEntryPoints(entryPoints, false));
Logger.LogInformation("Executed all post-startup entry points in {Elapsed:fff} ms", DateTime.Now - now);
}
private void RunEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
{
foreach (var entryPoint in entryPoints)
{
@ -688,22 +685,13 @@ namespace Emby.Server.Implementations
continue;
}
var name = entryPoint.GetType().FullName;
Logger.LogInformation("Starting entry point {Name}", name);
var now = DateTime.UtcNow;
try
{
entryPoint.Run();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error while running entrypoint {Name}", name);
}
Logger.LogInformation("Entry point completed: {Name}. Duration: {Duration} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
Logger.LogDebug("Starting entry point {Type}", entryPoint.GetType());
yield return entryPoint.RunAsync();
}
}
public void Init()
public async Task Init()
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@ -733,7 +721,7 @@ namespace Emby.Server.Implementations
SetHttpLimit();
RegisterResources();
await RegisterResources();
FindParts();
}
@ -748,7 +736,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
protected void RegisterResources()
protected async Task RegisterResources()
{
RegisterSingleInstance(ConfigurationManager);
RegisterSingleInstance<IApplicationHost>(this);
@ -780,9 +768,6 @@ namespace Emby.Server.Implementations
ProcessFactory = new ProcessFactory();
RegisterSingleInstance(ProcessFactory);
TimerFactory = new TimerFactory();
RegisterSingleInstance(TimerFactory);
var streamHelper = CreateStreamHelper();
ApplicationHost.StreamHelper = streamHelper;
RegisterSingleInstance(streamHelper);
@ -809,9 +794,9 @@ namespace Emby.Server.Implementations
IAssemblyInfo assemblyInfo = new AssemblyInfo();
RegisterSingleInstance(assemblyInfo);
LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory, assemblyInfo, new TextLocalizer());
StringExtensions.LocalizationManager = LocalizationManager;
RegisterSingleInstance(LocalizationManager);
LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory);
await LocalizationManager.LoadAll();
RegisterSingleInstance<ILocalizationManager>(LocalizationManager);
BlurayExaminer = new BdInfoExaminer(FileSystemManager);
RegisterSingleInstance(BlurayExaminer);
@ -845,7 +830,7 @@ namespace Emby.Server.Implementations
var musicManager = new MusicManager(LibraryManager);
RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager));
LibraryMonitor = new LibraryMonitor(LoggerFactory, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, TimerFactory, EnvironmentInfo);
LibraryMonitor = new LibraryMonitor(LoggerFactory, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, EnvironmentInfo);
RegisterSingleInstance(LibraryMonitor);
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LoggerFactory, LibraryManager, UserManager));
@ -877,7 +862,7 @@ namespace Emby.Server.Implementations
DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LoggerFactory, NetworkManager);
RegisterSingleInstance(DeviceManager);
MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, TimerFactory, () => MediaEncoder);
MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, () => MediaEncoder);
RegisterSingleInstance(MediaSourceManager);
SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager);
@ -892,7 +877,7 @@ namespace Emby.Server.Implementations
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LoggerFactory, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
RegisterSingleInstance(ChannelManager);
SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
RegisterSingleInstance(SessionManager);
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LoggerFactory, JsonSerializer, this, assemblyInfo);
@ -904,7 +889,7 @@ namespace Emby.Server.Implementations
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager);
RegisterSingleInstance(PlaylistManager);
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, () => ChannelManager);
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
RegisterSingleInstance(LiveTvManager);
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
@ -913,7 +898,7 @@ namespace Emby.Server.Implementations
NotificationManager = new NotificationManager(LoggerFactory, UserManager, ServerConfigurationManager);
RegisterSingleInstance(NotificationManager);
RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LoggerFactory, ServerConfigurationManager, SocketFactory, TimerFactory));
RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LoggerFactory, ServerConfigurationManager, SocketFactory));
ChapterManager = new ChapterManager(LibraryManager, LoggerFactory, ServerConfigurationManager, ItemRepository);
RegisterSingleInstance(ChapterManager);
@ -1671,7 +1656,6 @@ namespace Emby.Server.Implementations
var minRequiredVersions = new Dictionary<string, Version>(StringComparer.OrdinalIgnoreCase)
{
{ "GameBrowser.dll", new Version(3, 1) },
{ "moviethemesongs.dll", new Version(1, 6) },
{ "themesongs.dll", new Version(1, 2) }
};
@ -1747,7 +1731,7 @@ namespace Emby.Server.Implementations
EncoderLocationType = MediaEncoder.EncoderLocationType,
SystemArchitecture = EnvironmentInfo.SystemArchitecture,
SystemUpdateLevel = SystemUpdateLevel,
PackageName = StartupOptions.GetOption("-package")
PackageName = StartupOptions.PackageName
};
}

View file

@ -70,7 +70,8 @@ namespace Emby.Server.Implementations.Collections
return null;
})
.Where(i => i != null)
.DistinctBy(i => i.Id)
.GroupBy(x => x.Id)
.Select(x => x.First())
.OrderBy(i => Guid.NewGuid())
.ToList();
}

View file

@ -353,7 +353,7 @@ namespace Emby.Server.Implementations.Collections
_logger = logger;
}
public async void Run()
public async Task RunAsync()
{
if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
{

View file

@ -1239,10 +1239,6 @@ namespace Emby.Server.Implementations.Data
{
return false;
}
else if (type == typeof(GameGenre))
{
return false;
}
else if (type == typeof(Genre))
{
return false;
@ -3905,7 +3901,7 @@ namespace Emby.Server.Implementations.Data
// lowercase this because SortName is stored as lowercase
if (statement != null)
{
statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLower());
statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLowerInvariant());
}
}
if (!string.IsNullOrWhiteSpace(query.NameLessThan))
@ -3914,7 +3910,7 @@ namespace Emby.Server.Implementations.Data
// lowercase this because SortName is stored as lowercase
if (statement != null)
{
statement.TryBind("@NameLessThan", query.NameLessThan.ToLower());
statement.TryBind("@NameLessThan", query.NameLessThan.ToLowerInvariant());
}
}
@ -4789,10 +4785,6 @@ namespace Emby.Server.Implementations.Data
{
list.Add(typeof(MusicGenre).Name);
}
if (IsTypeInQuery(typeof(GameGenre).Name, query))
{
list.Add(typeof(GameGenre).Name);
}
if (IsTypeInQuery(typeof(MusicArtist).Name, query))
{
list.Add(typeof(MusicArtist).Name);
@ -4822,7 +4814,7 @@ namespace Emby.Server.Implementations.Data
return value;
}
return value.RemoveDiacritics().ToLower();
return value.RemoveDiacritics().ToLowerInvariant();
}
private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
@ -4891,9 +4883,6 @@ namespace Emby.Server.Implementations.Data
typeof(Book),
typeof(CollectionFolder),
typeof(Folder),
typeof(Game),
typeof(GameGenre),
typeof(GameSystem),
typeof(Genre),
typeof(Person),
typeof(Photo),
@ -5251,11 +5240,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName);
}
public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
{
return GetItemValues(query, new[] { 2 }, typeof(GameGenre).FullName);
}
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
{
return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName);
@ -5276,14 +5260,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return GetItemValueNames(new[] { 2 }, new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List<string>());
}
public List<string> GetGameGenreNames()
{
return GetItemValueNames(new[] { 2 }, new List<string> { "Game" }, new List<string>());
}
public List<string> GetGenreNames()
{
return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist", "Game", "GameSystem" });
return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" });
}
private List<string> GetItemValueNames(int[] itemValueTypes, List<string> withItemTypes, List<string> excludeItemTypes)
@ -5652,10 +5631,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
{
counts.SongCount = value;
}
else if (string.Equals(typeName, typeof(Game).FullName, StringComparison.OrdinalIgnoreCase))
{
counts.GameCount = value;
}
else if (string.Equals(typeName, typeof(Trailer).FullName, StringComparison.OrdinalIgnoreCase))
{
counts.TrailerCount = value;

View file

@ -425,7 +425,7 @@ namespace Emby.Server.Implementations.Devices
_logger = logger;
}
public async void Run()
public async Task RunAsync()
{
if (!_config.Configuration.CameraUploadUpgraded && _config.Configuration.IsStartupWizardCompleted)
{

View file

@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.Diagnostics
{
return _process.WaitForExit(timeMs);
}
public Task<bool> WaitForExitAsync(int timeMs)
{
//Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true.

View file

@ -374,10 +374,6 @@ namespace Emby.Server.Implementations.Dto
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
dto.SongCount = taggedItems.Count(i => i is Audio);
}
else if (item is GameGenre)
{
dto.GameCount = taggedItems.Count(i => i is Game);
}
else
{
// This populates them all and covers Genre, Person, Studio, Year
@ -385,7 +381,6 @@ namespace Emby.Server.Implementations.Dto
dto.ArtistCount = taggedItems.Count(i => i is MusicArtist);
dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum);
dto.EpisodeCount = taggedItems.Count(i => i is Episode);
dto.GameCount = taggedItems.Count(i => i is Game);
dto.MovieCount = taggedItems.Count(i => i is Movie);
dto.TrailerCount = taggedItems.Count(i => i is Trailer);
dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo);
@ -532,17 +527,6 @@ namespace Emby.Server.Implementations.Dto
dto.Album = item.Album;
}
private static void SetGameProperties(BaseItemDto dto, Game item)
{
dto.GameSystem = item.GameSystem;
dto.MultiPartGameFiles = item.MultiPartGameFiles;
}
private static void SetGameSystemProperties(BaseItemDto dto, GameSystem item)
{
dto.GameSystem = item.GameSystemName;
}
private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images)
{
return images
@ -636,7 +620,8 @@ namespace Emby.Server.Implementations.Dto
}
}).Where(i => i != null)
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
for (var i = 0; i < people.Count; i++)
@ -698,11 +683,6 @@ namespace Emby.Server.Implementations.Dto
return _libraryManager.GetMusicGenreId(name);
}
if (owner is Game || owner is GameSystem)
{
return _libraryManager.GetGameGenreId(name);
}
return _libraryManager.GetGenreId(name);
}
@ -1206,20 +1186,6 @@ namespace Emby.Server.Implementations.Dto
}
}
var game = item as Game;
if (game != null)
{
SetGameProperties(dto, game);
}
var gameSystem = item as GameSystem;
if (gameSystem != null)
{
SetGameSystemProperties(dto, gameSystem);
}
var musicVideo = item as MusicVideo;
if (musicVideo != null)
{
@ -1452,7 +1418,7 @@ namespace Emby.Server.Implementations.Dto
try
{
size = _imageProcessor.GetImageSize(item, imageInfo);
size = _imageProcessor.GetImageDimensions(item, imageInfo);
if (size.Width <= 0 || size.Height <= 0)
{

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" />
@ -25,8 +25,7 @@
<PackageReference Include="ServiceStack.Text.Core" Version="5.4.0" />
<PackageReference Include="sharpcompress" Version="0.22.0" />
<PackageReference Include="SimpleInjector" Version="4.4.2" />
<PackageReference Include="SQLitePCL.pretty.core" Version="1.1.8" />
<PackageReference Include="SQLitePCLRaw.core" Version="1.1.11" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="1.0.0" />
<PackageReference Include="UTF.Unknown" Version="1.0.0-beta1" />
</ItemGroup>
@ -43,7 +42,7 @@
<EmbeddedResource Include="Localization\iso6392.txt" />
<EmbeddedResource Include="Localization\countries.json" />
<EmbeddedResource Include="Localization\Core\*.json" />
<EmbeddedResource Include="Localization\Ratings\*.txt" />
<EmbeddedResource Include="Localization\Ratings\*.csv" />
</ItemGroup>
</Project>

View file

@ -9,7 +9,6 @@ using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@ -22,11 +21,10 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ISessionManager _sessionManager;
private readonly IServerConfigurationManager _config;
private readonly ILiveTvManager _liveTvManager;
private readonly ITimerFactory _timerFactory;
private ITimer _timer;
private Timer _timer;
public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager, ITimerFactory timerFactory)
public AutomaticRestartEntryPoint(IServerApplicationHost appHost, ILogger logger, ITaskManager iTaskManager, ISessionManager sessionManager, IServerConfigurationManager config, ILiveTvManager liveTvManager)
{
_appHost = appHost;
_logger = logger;
@ -34,15 +32,16 @@ namespace Emby.Server.Implementations.EntryPoints
_sessionManager = sessionManager;
_config = config;
_liveTvManager = liveTvManager;
_timerFactory = timerFactory;
}
public void Run()
public Task RunAsync()
{
if (_appHost.CanSelfRestart)
{
_appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged;
}
return Task.CompletedTask;
}
void _appHost_HasPendingRestartChanged(object sender, EventArgs e)
@ -51,7 +50,7 @@ namespace Emby.Server.Implementations.EntryPoints
if (_appHost.HasPendingRestart)
{
_timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15));
_timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15));
}
}

View file

@ -10,7 +10,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
using Mono.Nat;
@ -24,19 +23,17 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IServerConfigurationManager _config;
private readonly IDeviceDiscovery _deviceDiscovery;
private ITimer _timer;
private readonly ITimerFactory _timerFactory;
private Timer _timer;
private NatManager _natManager;
public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, ITimerFactory timerFactory)
public ExternalPortForwarding(ILoggerFactory loggerFactory, IServerApplicationHost appHost, IServerConfigurationManager config, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient)
{
_logger = loggerFactory.CreateLogger("PortMapper");
_appHost = appHost;
_config = config;
_deviceDiscovery = deviceDiscovery;
_httpClient = httpClient;
_timerFactory = timerFactory;
_config.ConfigurationUpdated += _config_ConfigurationUpdated1;
}
@ -61,17 +58,17 @@ namespace Emby.Server.Implementations.EntryPoints
return string.Join("|", values.ToArray());
}
void _config_ConfigurationUpdated(object sender, EventArgs e)
private async void _config_ConfigurationUpdated(object sender, EventArgs e)
{
if (!string.Equals(_lastConfigIdentifier, GetConfigIdentifier(), StringComparison.OrdinalIgnoreCase))
{
DisposeNat();
Run();
await RunAsync();
}
}
public void Run()
public Task RunAsync()
{
if (_config.Configuration.EnableUPnP && _config.Configuration.EnableRemoteAccess)
{
@ -80,6 +77,8 @@ namespace Emby.Server.Implementations.EntryPoints
_config.ConfigurationUpdated -= _config_ConfigurationUpdated;
_config.ConfigurationUpdated += _config_ConfigurationUpdated;
return Task.CompletedTask;
}
private void Start()
@ -92,7 +91,7 @@ namespace Emby.Server.Implementations.EntryPoints
_natManager.StartDiscovery();
}
_timer = _timerFactory.Create(ClearCreatedRules, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
_timer = new Timer(ClearCreatedRules, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@ -13,7 +14,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@ -28,7 +28,6 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager;
private readonly ILogger _logger;
private readonly ITimerFactory _timerFactory;
/// <summary>
/// The _library changed sync lock
@ -46,7 +45,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// Gets or sets the library update timer.
/// </summary>
/// <value>The library update timer.</value>
private ITimer LibraryUpdateTimer { get; set; }
private Timer LibraryUpdateTimer { get; set; }
/// <summary>
/// The library update duration
@ -55,17 +54,16 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IProviderManager _providerManager;
public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, ITimerFactory timerFactory, IProviderManager providerManager)
public LibraryChangedNotifier(ILibraryManager libraryManager, ISessionManager sessionManager, IUserManager userManager, ILogger logger, IProviderManager providerManager)
{
_libraryManager = libraryManager;
_sessionManager = sessionManager;
_userManager = userManager;
_logger = logger;
_timerFactory = timerFactory;
_providerManager = providerManager;
}
public void Run()
public Task RunAsync()
{
_libraryManager.ItemAdded += libraryManager_ItemAdded;
_libraryManager.ItemUpdated += libraryManager_ItemUpdated;
@ -74,6 +72,8 @@ namespace Emby.Server.Implementations.EntryPoints
_providerManager.RefreshCompleted += _providerManager_RefreshCompleted;
_providerManager.RefreshStarted += _providerManager_RefreshStarted;
_providerManager.RefreshProgress += _providerManager_RefreshProgress;
return Task.CompletedTask;
}
private Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>();
@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@ -222,7 +222,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@ -250,7 +250,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = _timerFactory.Create(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
@ -277,14 +277,21 @@ namespace Emby.Server.Implementations.EntryPoints
lock (_libraryChangedSyncLock)
{
// Remove dupes in case some were saved multiple times
var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList();
var foldersAddedTo = _foldersAddedTo
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToList();
var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList();
var foldersRemovedFrom = _foldersRemovedFrom
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToList();
var itemsUpdated = _itemsUpdated
.Where(i => !_itemsAdded.Contains(i))
.DistinctBy(i => i.Id)
.ToList();
.Where(i => !_itemsAdded.Contains(i))
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToList();
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);

View file

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Plugins;
@ -24,12 +25,14 @@ namespace Emby.Server.Implementations.EntryPoints
_liveTvManager = liveTvManager;
}
public void Run()
public Task RunAsync()
{
_liveTvManager.TimerCancelled += _liveTvManager_TimerCancelled;
_liveTvManager.SeriesTimerCancelled += _liveTvManager_SeriesTimerCancelled;
_liveTvManager.TimerCreated += _liveTvManager_TimerCreated;
_liveTvManager.SeriesTimerCreated += _liveTvManager_SeriesTimerCreated;
return Task.CompletedTask;
}
private void _liveTvManager_SeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs<TimerEventInfo> e)

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
@ -49,7 +50,7 @@ namespace Emby.Server.Implementations.EntryPoints
_sessionManager = sessionManager;
}
public void Run()
public Task RunAsync()
{
_userManager.UserDeleted += userManager_UserDeleted;
_userManager.UserUpdated += userManager_UserUpdated;
@ -65,6 +66,8 @@ namespace Emby.Server.Implementations.EntryPoints
_installationManager.PackageInstallationFailed += _installationManager_PackageInstallationFailed;
_taskManager.TaskCompleted += _taskManager_TaskCompleted;
return Task.CompletedTask;
}
void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)

View file

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Emby.Server.Implementations.Browser;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
@ -32,11 +33,11 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary>
/// Runs this instance.
/// </summary>
public void Run()
public Task RunAsync()
{
if (!_appHost.CanLaunchWebBrowser)
{
return;
return Task.CompletedTask;
}
if (!_config.Configuration.IsStartupWizardCompleted)
@ -47,11 +48,13 @@ namespace Emby.Server.Implementations.EntryPoints
{
var options = ((ApplicationHost)_appHost).StartupOptions;
if (!options.ContainsOption("-noautorunwebapp"))
if (!options.NoAutoRunWebApp)
{
BrowserLauncher.OpenWebApp(_appHost);
}
}
return Task.CompletedTask;
}
/// <summary>

View file

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Plugins;
@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary>
/// Runs this instance.
/// </summary>
public void Run()
public Task RunAsync()
{
var udpServer = new UdpServer(_logger, _appHost, _json, _socketFactory);
@ -57,6 +58,8 @@ namespace Emby.Server.Implementations.EntryPoints
{
_logger.LogError(ex, "Failed to start UDP Server");
}
return Task.CompletedTask;
}
/// <summary>

View file

@ -10,7 +10,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
@ -23,24 +22,24 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly IUserManager _userManager;
private readonly object _syncLock = new object();
private ITimer UpdateTimer { get; set; }
private readonly ITimerFactory _timerFactory;
private Timer UpdateTimer { get; set; }
private const int UpdateDuration = 500;
private readonly Dictionary<Guid, List<BaseItem>> _changedItems = new Dictionary<Guid, List<BaseItem>>();
public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager, ITimerFactory timerFactory)
public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager)
{
_userDataManager = userDataManager;
_sessionManager = sessionManager;
_logger = logger;
_userManager = userManager;
_timerFactory = timerFactory;
}
public void Run()
public Task RunAsync()
{
_userDataManager.UserDataSaved += _userDataManager_UserDataSaved;
return Task.CompletedTask;
}
void _userDataManager_UserDataSaved(object sender, UserDataSaveEventArgs e)
@ -54,7 +53,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (UpdateTimer == null)
{
UpdateTimer = _timerFactory.Create(UpdateTimerCallback, null, UpdateDuration,
UpdateTimer = new Timer(UpdateTimerCallback, null, UpdateDuration,
Timeout.Infinite);
}
else
@ -121,7 +120,8 @@ namespace Emby.Server.Implementations.EntryPoints
var user = _userManager.GetUserById(userId);
var dtoList = changedItems
.DistinctBy(i => i.Id)
.GroupBy(x => x.Id)
.Select(x => x.First())
.Select(i =>
{
var dto = _userDataManager.GetUserDataDto(i, user);

View file

@ -28,10 +28,10 @@ namespace Emby.Server.Implementations.FFMpeg
_ffmpegInstallInfo = ffmpegInstallInfo;
}
public FFMpegInfo GetFFMpegInfo(StartupOptions options)
public FFMpegInfo GetFFMpegInfo(IStartupOptions options)
{
var customffMpegPath = options.GetOption("-ffmpeg");
var customffProbePath = options.GetOption("-ffprobe");
var customffMpegPath = options.FFmpegPath;
var customffProbePath = options.FFprobePath;
if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath))
{

View file

@ -264,7 +264,7 @@ namespace Emby.Server.Implementations.HttpClientManager
}
var url = options.Url;
var urlHash = url.ToLower().GetMD5().ToString("N");
var urlHash = url.ToLowerInvariant().GetMD5().ToString("N");
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
@ -374,11 +374,11 @@ namespace Emby.Server.Implementations.HttpClientManager
{
if (options.LogRequestAsDebug)
{
_logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url);
_logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
}
else
{
_logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url);
_logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url);
}
}

View file

@ -394,7 +394,7 @@ namespace Emby.Server.Implementations.HttpServer
{
return contentType == null
? null
: contentType.Split(';')[0].ToLower().Trim();
: contentType.Split(';')[0].ToLowerInvariant().Trim();
}
private static string SerializeToXmlString(object from)

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@ -9,7 +10,6 @@ using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.IO
@ -22,8 +22,7 @@ namespace Emby.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
private readonly List<string> _affectedPaths = new List<string>();
private ITimer _timer;
private readonly ITimerFactory _timerFactory;
private Timer _timer;
private readonly object _timerLock = new object();
public string Path { get; private set; }
@ -31,7 +30,7 @@ namespace Emby.Server.Implementations.IO
private readonly IEnvironmentInfo _environmentInfo;
private readonly ILibraryManager _libraryManager;
public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, ITimerFactory timerFactory, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
public FileRefresher(string path, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ITaskManager taskManager, ILogger logger, IEnvironmentInfo environmentInfo, ILibraryManager libraryManager1)
{
logger.LogDebug("New file refresher created for {0}", path);
Path = path;
@ -41,7 +40,6 @@ namespace Emby.Server.Implementations.IO
LibraryManager = libraryManager;
TaskManager = taskManager;
Logger = logger;
_timerFactory = timerFactory;
_environmentInfo = environmentInfo;
_libraryManager = libraryManager1;
AddPath(path);
@ -90,7 +88,7 @@ namespace Emby.Server.Implementations.IO
if (_timer == null)
{
_timer = _timerFactory.Create(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
_timer = new Timer(OnTimerCallback, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.LibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
}
else
{
@ -146,8 +144,8 @@ namespace Emby.Server.Implementations.IO
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(GetAffectedBaseItem)
.Where(item => item != null)
.DistinctBy(i => i.Id)
.ToList();
.GroupBy(x => x.Id)
.Select(x => x.First());
foreach (var item in itemsToRefresh)
{

View file

@ -11,7 +11,6 @@ using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.IO
@ -35,7 +34,7 @@ namespace Emby.Server.Implementations.IO
/// <summary>
/// Any file name ending in any of these will be ignored by the watchers
/// </summary>
private readonly string[] _alwaysIgnoreFiles = new string[]
private readonly HashSet<string> _alwaysIgnoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"small.jpg",
"albumart.jpg",
@ -54,7 +53,7 @@ namespace Emby.Server.Implementations.IO
".actors"
};
private readonly string[] _alwaysIgnoreExtensions = new string[]
private readonly HashSet<string> _alwaysIgnoreExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
// thumbs.db
".db",
@ -134,7 +133,6 @@ namespace Emby.Server.Implementations.IO
private IServerConfigurationManager ConfigurationManager { get; set; }
private readonly IFileSystem _fileSystem;
private readonly ITimerFactory _timerFactory;
private readonly IEnvironmentInfo _environmentInfo;
/// <summary>
@ -146,7 +144,6 @@ namespace Emby.Server.Implementations.IO
ILibraryManager libraryManager,
IServerConfigurationManager configurationManager,
IFileSystem fileSystem,
ITimerFactory timerFactory,
IEnvironmentInfo environmentInfo)
{
if (taskManager == null)
@ -159,7 +156,6 @@ namespace Emby.Server.Implementations.IO
Logger = loggerFactory.CreateLogger(GetType().Name);
ConfigurationManager = configurationManager;
_fileSystem = fileSystem;
_timerFactory = timerFactory;
_environmentInfo = environmentInfo;
}
@ -460,8 +456,8 @@ namespace Emby.Server.Implementations.IO
var filename = Path.GetFileName(path);
var monitorPath = !string.IsNullOrEmpty(filename) &&
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase) &&
!_alwaysIgnoreFiles.Contains(filename) &&
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path)) &&
_alwaysIgnoreSubstrings.All(i => path.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1);
// Ignore certain files
@ -545,7 +541,7 @@ namespace Emby.Server.Implementations.IO
}
}
var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _timerFactory, _environmentInfo, LibraryManager);
var newRefresher = new FileRefresher(path, _fileSystem, ConfigurationManager, LibraryManager, TaskManager, Logger, _environmentInfo, LibraryManager);
newRefresher.Completed += NewRefresher_Completed;
_activeRefreshers.Add(newRefresher);
}
@ -601,20 +597,26 @@ namespace Emby.Server.Implementations.IO
/// </summary>
public void Dispose()
{
_disposed = true;
Dispose(true);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (dispose)
if (_disposed)
{
return;
}
if (disposing)
{
Stop();
}
_disposed = true;
}
}
@ -627,9 +629,10 @@ namespace Emby.Server.Implementations.IO
_monitor = monitor;
}
public void Run()
public Task RunAsync()
{
_monitor.Start();
return Task.CompletedTask;
}
public void Dispose()

View file

@ -0,0 +1,40 @@
namespace Emby.Server.Implementations
{
public interface IStartupOptions
{
/// <summary>
/// --ffmpeg
/// </summary>
string FFmpegPath { get; }
/// <summary>
/// --ffprobe
/// </summary>
string FFprobePath { get; }
/// <summary>
/// --service
/// </summary>
bool IsService { get; }
/// <summary>
/// --noautorunwebapp
/// </summary>
bool NoAutoRunWebApp { get; }
/// <summary>
/// --package-name
/// </summary>
string PackageName { get; }
/// <summary>
/// --restartpath
/// </summary>
string RestartPath { get; }
/// <summary>
/// --restartargs
/// </summary>
string RestartArgs { get; }
}
}

View file

@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.Images
{
return CreateSquareCollage(item, itemsWithImages, outputPath);
}
if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum)
if (item is Playlist || item is MusicGenre || item is Genre || item is PhotoAlbum)
{
return CreateSquareCollage(item, itemsWithImages, outputPath);
}

View file

@ -512,7 +512,7 @@ namespace Emby.Server.Implementations.Library
if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
{
key = key.ToLower();
key = key.ToLowerInvariant();
}
key = type.FullName + key;
@ -869,11 +869,6 @@ namespace Emby.Server.Implementations.Library
return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name);
}
public Guid GetGameGenreId(string name)
{
return GetItemByNameId<GameGenre>(GameGenre.GetPath, name);
}
/// <summary>
/// Gets a Genre
/// </summary>
@ -894,16 +889,6 @@ namespace Emby.Server.Implementations.Library
return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
/// Gets the game genre.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>Task{GameGenre}.</returns>
public GameGenre GetGameGenre(string name)
{
return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true));
}
/// <summary>
/// Gets a Year
/// </summary>
@ -1370,17 +1355,6 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetGenres(query);
}
public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
{
if (query.User != null)
{
AddUserToQuery(query, query.User);
}
SetTopParentOrAncestorIds(query);
return ItemRepository.GetGameGenres(query);
}
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
{
if (query.User != null)

View file

@ -20,7 +20,6 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library
@ -36,7 +35,6 @@ namespace Emby.Server.Implementations.Library
private IMediaSourceProvider[] _providers;
private readonly ILogger _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITimerFactory _timerFactory;
private readonly Func<IMediaEncoder> _mediaEncoder;
private ILocalizationManager _localizationManager;
private IApplicationPaths _appPaths;
@ -51,7 +49,6 @@ namespace Emby.Server.Implementations.Library
IJsonSerializer jsonSerializer,
IFileSystem fileSystem,
IUserDataManager userDataManager,
ITimerFactory timerFactory,
Func<IMediaEncoder> mediaEncoder)
{
_itemRepo = itemRepo;
@ -61,7 +58,6 @@ namespace Emby.Server.Implementations.Library
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem;
_userDataManager = userDataManager;
_timerFactory = timerFactory;
_mediaEncoder = mediaEncoder;
_localizationManager = localizationManager;
_appPaths = applicationPaths;
@ -322,18 +318,18 @@ namespace Emby.Server.Implementations.Library
private string[] NormalizeLanguage(string language)
{
if (language != null)
if (language == null)
{
var culture = _localizationManager.FindLanguageInfo(language);
if (culture != null)
{
return culture.ThreeLetterISOLanguageNames;
}
return new string[] { language };
return Array.Empty<string>();
}
return Array.Empty<string>();
var culture = _localizationManager.FindLanguageInfo(language);
if (culture != null)
{
return culture.ThreeLetterISOLanguageNames;
}
return new string[] { language };
}
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Drawing;
@ -85,7 +86,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
private static readonly string[] IgnoreFiles =
private static readonly HashSet<string> IgnoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"folder",
"thumb",
@ -102,7 +103,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
var filename = Path.GetFileNameWithoutExtension(path) ?? string.Empty;
if (IgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
if (IgnoreFiles.Contains(filename))
{
return false;
}
@ -112,7 +113,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return false;
}
return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'), StringComparer.OrdinalIgnoreCase);
return imageProcessor.SupportedInputFormats.Contains((Path.GetExtension(path) ?? string.Empty).TrimStart('.'));
}
}

View file

@ -99,14 +99,12 @@ namespace Emby.Server.Implementations.Library
if (!query.IncludeMedia)
{
AddIfMissing(includeItemTypes, typeof(Genre).Name);
AddIfMissing(includeItemTypes, typeof(GameGenre).Name);
AddIfMissing(includeItemTypes, typeof(MusicGenre).Name);
}
}
else
{
AddIfMissing(excludeItemTypes, typeof(Genre).Name);
AddIfMissing(excludeItemTypes, typeof(GameGenre).Name);
AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name);
}

View file

@ -24,7 +24,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Connect;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@ -212,11 +211,8 @@ namespace Emby.Server.Implementations.Library
{
foreach (var user in users)
{
if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser)
{
user.Policy.IsAdministrator = true;
UpdateUserPolicy(user, user.Policy, false);
}
user.Policy.IsAdministrator = true;
UpdateUserPolicy(user, user.Policy, false);
}
}
}
@ -272,13 +268,9 @@ namespace Emby.Server.Implementations.Library
if (user != null)
{
// Authenticate using local credentials if not a guest
if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest)
{
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
authenticationProvider = authResult.Item1;
success = authResult.Item2;
}
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
authenticationProvider = authResult.Item1;
success = authResult.Item2;
}
else
{
@ -455,30 +447,30 @@ namespace Emby.Server.Implementations.Library
private void UpdateInvalidLoginAttemptCount(User user, int newValue)
{
if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
if (user.Policy.InvalidLoginAttemptCount == newValue || newValue <= 0)
{
user.Policy.InvalidLoginAttemptCount = newValue;
return;
}
var maxCount = user.Policy.IsAdministrator ? 3 : 5;
user.Policy.InvalidLoginAttemptCount = newValue;
// TODO: Fix
/*
var fireLockout = false;
var maxCount = user.Policy.IsAdministrator ? 3 : 5;
if (newValue >= maxCount)
{
_logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
user.Policy.IsDisabled = true;
var fireLockout = false;
fireLockout = true;
}*/
if (newValue >= maxCount)
{
_logger.LogDebug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue);
user.Policy.IsDisabled = true;
UpdateUserPolicy(user, user.Policy, false);
fireLockout = true;
}
/* if (fireLockout)
{
UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
}*/
UpdateUserPolicy(user, user.Policy, false);
if (fireLockout)
{
UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
}
}
@ -553,9 +545,6 @@ namespace Emby.Server.Implementations.Library
LastActivityDate = user.LastActivityDate,
LastLoginDate = user.LastLoginDate,
Configuration = user.Configuration,
ConnectLinkType = user.ConnectLinkType,
ConnectUserId = user.ConnectUserId,
ConnectUserName = user.ConnectUserName,
ServerId = _appHost.SystemId,
Policy = user.Policy
};
@ -814,11 +803,6 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(user));
}
if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
{
throw new ArgumentException("Passwords for guests cannot be changed.");
}
await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false);
UpdateUser(user);
@ -925,11 +909,6 @@ namespace Emby.Server.Implementations.Library
null :
GetUserByName(enteredUsername);
if (user != null && user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest)
{
throw new ArgumentException("Unable to process forgot password request for guests.");
}
var action = ForgotPasswordAction.InNetworkRequired;
string pinFile = null;
DateTime? expirationDate = null;
@ -974,10 +953,7 @@ namespace Emby.Server.Implementations.Library
_lastPin = null;
_lastPasswordPinCreationResult = null;
var users = Users.Where(i => !i.ConnectLinkType.HasValue || i.ConnectLinkType.Value != UserLinkType.Guest)
.ToList();
foreach (var user in users)
foreach (var user in Users)
{
await ResetPassword(user).ConfigureAwait(false);
@ -1205,9 +1181,11 @@ namespace Emby.Server.Implementations.Library
_sessionManager = sessionManager;
}
public void Run()
public Task RunAsync()
{
_userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated;
return Task.CompletedTask;
}
private void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)

View file

@ -308,9 +308,6 @@ namespace Emby.Server.Implementations.Library
mediaTypes.Add(MediaType.Book);
mediaTypes.Add(MediaType.Audio);
break;
case CollectionType.Games:
mediaTypes.Add(MediaType.Game);
break;
case CollectionType.Music:
mediaTypes.Add(MediaType.Audio);
break;
@ -336,7 +333,6 @@ namespace Emby.Server.Implementations.Library
typeof(Person).Name,
typeof(Studio).Name,
typeof(Year).Name,
typeof(GameGenre).Name,
typeof(MusicGenre).Name,
typeof(Genre).Name

View file

@ -1,45 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class GameGenresPostScanTask
/// </summary>
public class GameGenresPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// The _library manager
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken);
}
}
}

View file

@ -1,72 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
class GameGenresValidator
{
/// <summary>
/// The _library manager
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The _logger
/// </summary>
private readonly ILogger _logger;
private readonly IItemRepository _itemRepo;
public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;
_logger = logger;
_itemRepo = itemRepo;
}
/// <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.GetGameGenreNames();
var numComplete = 0;
var count = names.Count;
foreach (var name in names)
{
try
{
var item = _libraryManager.GetGameGenre(name);
await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Don't clutter the log
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error refreshing {GenreName}", name);
}
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
progress.Report(percent);
}
progress.Report(100);
}
}
}

View file

@ -35,8 +35,6 @@ using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Reflection;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
@ -65,7 +63,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public static EmbyTV Current;
public event EventHandler DataSourceChanged;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerCreated;
public event EventHandler<GenericEventArgs<string>> TimerCancelled;
@ -88,7 +85,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
ILibraryMonitor libraryMonitor,
IProviderManager providerManager,
IMediaEncoder mediaEncoder,
ITimerFactory timerFactory,
IProcessFactory processFactory)
{
Current = this;
@ -110,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_streamHelper = streamHelper;
_seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
_timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), _logger, timerFactory);
_timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), _logger);
_timerProvider.TimerFired += _timerProvider_TimerFired;
_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
@ -124,7 +120,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
public async void Start()
public async Task Start()
{
_timerProvider.RestartTimers();
@ -275,7 +271,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
foreach (var timer in seriesTimers)
{
await UpdateTimersForSeriesTimer(timer, false, true).ConfigureAwait(false);
UpdateTimersForSeriesTimer(timer, false, true);
}
}
@ -763,12 +759,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer, false);
}
await UpdateTimersForSeriesTimer(info, true, false).ConfigureAwait(false);
UpdateTimersForSeriesTimer(info, true, false);
return info.Id;
}
public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
public Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{
var instance = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
@ -792,8 +788,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_seriesTimerProvider.Update(instance);
await UpdateTimersForSeriesTimer(instance, true, true).ConfigureAwait(false);
UpdateTimersForSeriesTimer(instance, true, true);
}
return Task.CompletedTask;
}
public Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken)
@ -2193,7 +2191,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (lockData)
{
writer.WriteElementString("lockdata", true.ToString().ToLower());
writer.WriteElementString("lockdata", true.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
}
if (item.CriticRating.HasValue)
@ -2346,10 +2344,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers)
private void UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers)
{
var allTimers = GetTimersForSeries(seriesTimer)
.ToList();
var allTimers = GetTimersForSeries(seriesTimer).ToList();
var enabledTimersForSeries = new List<TimerInfo>();

View file

@ -1,12 +1,13 @@
using System.Threading.Tasks;
using MediaBrowser.Controller.Plugins;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class EntryPoint : IServerEntryPoint
{
public void Run()
public Task RunAsync()
{
EmbyTV.Current.Start();
return EmbyTV.Current.Start();
}
public void Dispose()

View file

@ -2,29 +2,27 @@ using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Threading;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class TimerManager : ItemDataProvider<TimerInfo>
{
private readonly ConcurrentDictionary<string, ITimer> _timers = new ConcurrentDictionary<string, ITimer>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, Timer> _timers = new ConcurrentDictionary<string, Timer>(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
private readonly ITimerFactory _timerFactory;
public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, ILogger logger1, ITimerFactory timerFactory)
public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, ILogger logger1)
: base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
{
_logger = logger1;
_timerFactory = timerFactory;
}
public void RestartTimers()
@ -125,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private void StartTimer(TimerInfo item, TimeSpan dueTime)
{
var timer = _timerFactory.Create(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
var timer = new Timer(TimerCallback, item.Id, dueTime, TimeSpan.Zero);
if (_timers.TryAdd(item.Id, timer))
{

View file

@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Implementations.LiveTv.Listings
namespace Emby.Server.Implementations.LiveTv.Listings
{
public class XmlTvListingsProvider : IListingsProvider
{

View file

@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var name = serviceName + externalId + InternalVersionNumber;
return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvChannel));
return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvChannel));
}
private const string ServiceName = "Emby";
@ -407,21 +407,21 @@ namespace Emby.Server.Implementations.LiveTv
{
var name = ServiceName + externalId + InternalVersionNumber;
return name.ToLower().GetMD5().ToString("N");
return name.ToLowerInvariant().GetMD5().ToString("N");
}
public Guid GetInternalSeriesTimerId(string externalId)
{
var name = ServiceName + externalId + InternalVersionNumber;
return name.ToLower().GetMD5();
return name.ToLowerInvariant().GetMD5();
}
public Guid GetInternalProgramId(string externalId)
{
var name = ServiceName + externalId + InternalVersionNumber;
return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvProgram));
return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvProgram));
}
public async Task<TimerInfo> GetTimerInfo(TimerInfoDto dto, bool isNew, LiveTvManager liveTv, CancellationToken cancellationToken)

View file

@ -6,7 +6,6 @@ using System.Threading.Tasks;
using Emby.Server.Implementations.Library;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
@ -24,7 +23,6 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
@ -48,7 +46,6 @@ namespace Emby.Server.Implementations.LiveTv
private readonly ILibraryManager _libraryManager;
private readonly ITaskManager _taskManager;
private readonly IJsonSerializer _jsonSerializer;
private readonly IProviderManager _providerManager;
private readonly Func<IChannelManager> _channelManager;
private readonly IDtoService _dtoService;
@ -56,7 +53,7 @@ namespace Emby.Server.Implementations.LiveTv
private readonly LiveTvDtoService _tvDtoService;
private ILiveTvService[] _services = new ILiveTvService[] { };
private ILiveTvService[] _services = Array.Empty<ILiveTvService>();
private ITunerHost[] _tunerHosts = Array.Empty<ITunerHost>();
private IListingsProvider[] _listingProviders = Array.Empty<IListingsProvider>();
@ -85,7 +82,6 @@ namespace Emby.Server.Implementations.LiveTv
ITaskManager taskManager,
ILocalizationManager localization,
IJsonSerializer jsonSerializer,
IProviderManager providerManager,
IFileSystem fileSystem,
Func<IChannelManager> channelManager)
{
@ -97,7 +93,6 @@ namespace Emby.Server.Implementations.LiveTv
_taskManager = taskManager;
_localization = localization;
_jsonSerializer = jsonSerializer;
_providerManager = providerManager;
_fileSystem = fileSystem;
_dtoService = dtoService;
_userDataManager = userDataManager;
@ -132,8 +127,6 @@ namespace Emby.Server.Implementations.LiveTv
foreach (var service in _services)
{
service.DataSourceChanged += service_DataSourceChanged;
if (service is EmbyTV.EmbyTV embyTv)
{
embyTv.TimerCreated += EmbyTv_TimerCreated;
@ -189,14 +182,6 @@ namespace Emby.Server.Implementations.LiveTv
return EmbyTV.EmbyTV.Current.DiscoverTuners(newDevicesOnly, cancellationToken);
}
void service_DataSourceChanged(object sender, EventArgs e)
{
if (!_isDisposed)
{
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
}
}
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
{
var user = query.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(query.UserId);
@ -2158,17 +2143,28 @@ namespace Emby.Server.Implementations.LiveTv
Dispose(true);
}
private bool _isDisposed = false;
private bool _disposed = false;
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (_disposed)
{
return;
}
if (dispose)
{
_isDisposed = true;
// TODO: Dispose stuff
}
_services = null;
_listingProviders = null;
_tunerHosts = null;
_disposed = true;
}
private LiveTvServiceInfo[] GetServiceInfos()
@ -2469,7 +2465,8 @@ namespace Emby.Server.Implementations.LiveTv
.Where(i => i != null)
.Where(i => i.IsVisibleStandalone(user))
.SelectMany(i => _libraryManager.GetCollectionFolders(i))
.DistinctBy(i => i.Id)
.GroupBy(x => x.Id)
.Select(x => x.First())
.OrderBy(i => i.SortName)
.ToList();

View file

@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var now = DateTime.UtcNow;
StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
var _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
//OpenedMediaSource.Protocol = MediaProtocol.File;
//OpenedMediaSource.Path = tempFile;

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}",
"Favorites": "المفضلات",
"Folders": "المجلدات",
"Games": "الألعاب",
"Genres": "أنواع الأفلام",
"HeaderAlbumArtists": "فنانو الألبومات",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي",
"NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
"NotificationOptionCameraImageUploaded": "تم رقع صورة الكاميرا",
"NotificationOptionGamePlayback": "تم تشغيل اللعبة",
"NotificationOptionGamePlaybackStopped": "تم إيقاف تشغيل اللعبة",
"NotificationOptionInstallationFailed": "عملية التنصيب فشلت",
"NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
"NotificationOptionPluginError": "فشل في الملحق",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Любими",
"Folders": "Папки",
"Games": "Игри",
"Genres": "Жанрове",
"HeaderAlbumArtists": "Изпълнители на албуми",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Възпроизвеждането на звук започна",
"NotificationOptionAudioPlaybackStopped": "Възпроизвеждането на звук е спряно",
"NotificationOptionCameraImageUploaded": "Изображението от фотоапарата е качено",
"NotificationOptionGamePlayback": "Възпроизвеждането на играта започна",
"NotificationOptionGamePlaybackStopped": "Възпроизвеждането на играта е спряна",
"NotificationOptionInstallationFailed": "Неуспешно инсталиране",
"NotificationOptionNewLibraryContent": "Добавено е ново съдържание",
"NotificationOptionPluginError": "Грешка в приставка",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Intent de connexió fallit des de {0}",
"Favorites": "Preferits",
"Folders": "Directoris",
"Games": "Jocs",
"Genres": "Gèneres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Un component ha fallat",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neúspěšný pokus o přihlášení z {0}",
"Favorites": "Oblíbené",
"Folders": "Složky",
"Games": "Hry",
"Genres": "Žánry",
"HeaderAlbumArtists": "Umělci alba",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Přehrávání audia zahájeno",
"NotificationOptionAudioPlaybackStopped": "Přehrávání audia ukončeno",
"NotificationOptionCameraImageUploaded": "Kamerový záznam nahrán",
"NotificationOptionGamePlayback": "Spuštění hry zahájeno",
"NotificationOptionGamePlaybackStopped": "Hra ukončena",
"NotificationOptionInstallationFailed": "Chyba instalace",
"NotificationOptionNewLibraryContent": "Přidán nový obsah",
"NotificationOptionPluginError": "Chyba zásuvného modulu",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Fejlet loginforsøg fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
"Games": "Spil",
"Genres": "Genre",
"HeaderAlbumArtists": "Albumkunstnere",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audioafspilning påbegyndt",
"NotificationOptionAudioPlaybackStopped": "Audioafspilning stoppet",
"NotificationOptionCameraImageUploaded": "Kamerabillede uploadet",
"NotificationOptionGamePlayback": "Afspilning af Spil påbegyndt",
"NotificationOptionGamePlaybackStopped": "Afspilning af Spil stoppet",
"NotificationOptionInstallationFailed": "Installationsfejl",
"NotificationOptionNewLibraryContent": "Nyt indhold tilføjet",
"NotificationOptionPluginError": "Pluginfejl",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
"Favorites": "Favoriten",
"Folders": "Verzeichnisse",
"Games": "Spiele",
"Genres": "Genres",
"HeaderAlbumArtists": "Album-Künstler",
"HeaderCameraUploads": "Kamera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
"NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
"NotificationOptionCameraImageUploaded": "Kamera Bild hochgeladen",
"NotificationOptionGamePlayback": "Spielwiedergabe gestartet",
"NotificationOptionGamePlaybackStopped": "Spielwiedergabe gestoppt",
"NotificationOptionInstallationFailed": "Installationsfehler",
"NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
"NotificationOptionPluginError": "Plugin Fehler",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Αποτυχημένη προσπάθεια σύνδεσης από {0}",
"Favorites": "Αγαπημένα",
"Folders": "Φάκελοι",
"Games": "Παιχνίδια",
"Genres": "Είδη",
"HeaderAlbumArtists": "Άλμπουμ Καλλιτεχνών",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Η αναπαραγωγή ήχου ξεκίνησε",
"NotificationOptionAudioPlaybackStopped": "Η αναπαραγωγή ήχου σταμάτησε",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Η αναπαραγωγή του παιχνιδιού ξεκίνησε",
"NotificationOptionGamePlaybackStopped": "Η αναπαραγωγή του παιχνιδιού σταμάτησε",
"NotificationOptionInstallationFailed": "Αποτυχία εγκατάστασης",
"NotificationOptionNewLibraryContent": "Προστέθηκε νέο περιεχόμενο",
"NotificationOptionPluginError": "Αποτυχία του plugin",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favourites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Games": "Juegos",
"Genres": "Géneros",
"HeaderAlbumArtists": "Artistas del Álbum",
"HeaderCameraUploads": "Subidos desde Camara",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reproducción de audio iniciada",
"NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida",
"NotificationOptionCameraImageUploaded": "Imagen de la cámara subida",
"NotificationOptionGamePlayback": "Ejecución de juego iniciada",
"NotificationOptionGamePlaybackStopped": "Ejecución de juego detenida",
"NotificationOptionInstallationFailed": "Falla de instalación",
"NotificationOptionNewLibraryContent": "Nuevo contenido agregado",
"NotificationOptionPluginError": "Falla de complemento",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión a partir de {0}",
"Favorites": "Favoritos",
"Folders": "Carpetas",
"Games": "Juegos",
"Genres": "Géneros",
"HeaderAlbumArtists": "Artistas del Álbum",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Se inició la reproducción de audio",
"NotificationOptionAudioPlaybackStopped": "Se detuvo la reproducción de audio",
"NotificationOptionCameraImageUploaded": "Imagen de la cámara cargada",
"NotificationOptionGamePlayback": "Se inició la reproducción del juego",
"NotificationOptionGamePlaybackStopped": "Se detuvo la reproducción del juego",
"NotificationOptionInstallationFailed": "Error de instalación",
"NotificationOptionNewLibraryContent": "Nuevo contenido añadido",
"NotificationOptionPluginError": "Error en plugin",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود",
"Favorites": "مورد علاقه ها",
"Folders": "پوشه ها",
"Games": "بازی ها",
"Genres": "ژانرها",
"HeaderAlbumArtists": "هنرمندان آلبوم",
"HeaderCameraUploads": "آپلودهای دوربین",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "پخش صدا آغاز شد",
"NotificationOptionAudioPlaybackStopped": "پخش صدا متوقف شد",
"NotificationOptionCameraImageUploaded": "تصاویر دوربین آپلود شد",
"NotificationOptionGamePlayback": "پخش بازی آغاز شد",
"NotificationOptionGamePlaybackStopped": "پخش بازی متوقف شد",
"NotificationOptionInstallationFailed": "شکست نصب",
"NotificationOptionNewLibraryContent": "محتوای جدید افزوده شد",
"NotificationOptionPluginError": "خرابی افزونه",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Échec d'une tentative de connexion de {0}",
"Favorites": "Favoris",
"Folders": "Dossiers",
"Games": "Jeux",
"Genres": "Genres",
"HeaderAlbumArtists": "Artistes de l'album",
"HeaderCameraUploads": "Photos transférées",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Lecture audio démarrée",
"NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée",
"NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée",
"NotificationOptionGamePlayback": "Lecture de jeu démarrée",
"NotificationOptionGamePlaybackStopped": "Lecture de jeu arrêtée",
"NotificationOptionInstallationFailed": "Échec d'installation",
"NotificationOptionNewLibraryContent": "Nouveau contenu ajouté",
"NotificationOptionPluginError": "Erreur d'extension",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Spiel",
"Genres": "Genres",
"HeaderAlbumArtists": "Albuminterprete",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "משחקים",
"Genres": "ז'אנרים",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave za {0}",
"Favorites": "Omiljeni",
"Folders": "Mape",
"Games": "Igre",
"Genres": "Žanrovi",
"HeaderAlbumArtists": "Izvođači albuma",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reprodukcija glazbe započeta",
"NotificationOptionAudioPlaybackStopped": "Reprodukcija audiozapisa je zaustavljena",
"NotificationOptionCameraImageUploaded": "Slike kamere preuzete",
"NotificationOptionGamePlayback": "Igrica pokrenuta",
"NotificationOptionGamePlaybackStopped": "Reprodukcija igre je zaustavljena",
"NotificationOptionInstallationFailed": "Instalacija nije izvršena",
"NotificationOptionNewLibraryContent": "Novi sadržaj je dodan",
"NotificationOptionPluginError": "Dodatak otkazao",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Kedvencek",
"Folders": "Könyvtárak",
"Games": "Játékok",
"Genres": "Műfajok",
"HeaderAlbumArtists": "Album Előadók",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
"NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve",
"NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Telepítési hiba",
"NotificationOptionNewLibraryContent": "Új tartalom hozzáadva",
"NotificationOptionPluginError": "Bővítmény hiba",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da {0}",
"Favorites": "Preferiti",
"Folders": "Cartelle",
"Games": "Giochi",
"Genres": "Generi",
"HeaderAlbumArtists": "Artisti Album",
"HeaderCameraUploads": "Caricamenti Fotocamera",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "La riproduzione audio è iniziata",
"NotificationOptionAudioPlaybackStopped": "La riproduzione audio è stata interrotta",
"NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata",
"NotificationOptionGamePlayback": "Il gioco è stato avviato",
"NotificationOptionGamePlaybackStopped": "Il gioco è stato fermato",
"NotificationOptionInstallationFailed": "Installazione fallita",
"NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto",
"NotificationOptionPluginError": "Errore del Plug-in",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "{0} тарапынан кіру әрекеті сәтсіз",
"Favorites": "Таңдаулылар",
"Folders": "Қалталар",
"Games": "Ойындар",
"Genres": "Жанрлар",
"HeaderAlbumArtists": "Альбом орындаушылары",
"HeaderCameraUploads": "Камерадан жүктелгендер",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Дыбыс ойнатуы басталды",
"NotificationOptionAudioPlaybackStopped": "Дыбыс ойнатуы тоқтатылды",
"NotificationOptionCameraImageUploaded": "Камерадан фотосурет кері қотарылған",
"NotificationOptionGamePlayback": "Ойын ойнатуы басталды",
"NotificationOptionGamePlaybackStopped": "Ойын ойнатуы тоқтатылды",
"NotificationOptionInstallationFailed": "Орнату сәтсіздігі",
"NotificationOptionNewLibraryContent": "Жаңа мазмұн үстелген",
"NotificationOptionPluginError": "Плагин сәтсіздігі",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "앨범 아티스트",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Žanrai",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Mislykket påloggingsforsøk fra {0}",
"Favorites": "Favoritter",
"Folders": "Mapper",
"Games": "Spill",
"Genres": "Sjanger",
"HeaderAlbumArtists": "Albumartist",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Lyd tilbakespilling startet",
"NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet",
"NotificationOptionCameraImageUploaded": "Kamera bilde lastet opp",
"NotificationOptionGamePlayback": "Spill avspillingen startet",
"NotificationOptionGamePlaybackStopped": "Filmer",
"NotificationOptionInstallationFailed": "Installasjon feil",
"NotificationOptionNewLibraryContent": "Ny innhold er lagt til",
"NotificationOptionPluginError": "Plugin feil",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}",
"Favorites": "Favorieten",
"Folders": "Mappen",
"Games": "Spellen",
"Genres": "Genres",
"HeaderAlbumArtists": "Album artiesten",
"HeaderCameraUploads": "Camera uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Geluid gestart",
"NotificationOptionAudioPlaybackStopped": "Geluid gestopt",
"NotificationOptionCameraImageUploaded": "Camera afbeelding geüpload",
"NotificationOptionGamePlayback": "Spel gestart",
"NotificationOptionGamePlaybackStopped": "Spel gestopt",
"NotificationOptionInstallationFailed": "Installatie mislukt",
"NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
"NotificationOptionPluginError": "Plug-in fout",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Próba logowania przez {0} zakończona niepowodzeniem",
"Favorites": "Ulubione",
"Folders": "Foldery",
"Games": "Gry",
"Genres": "Gatunki",
"HeaderAlbumArtists": "Wykonawcy albumów",
"HeaderCameraUploads": "Przekazane obrazy",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki",
"NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane",
"NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia mobilnego",
"NotificationOptionGamePlayback": "Odtwarzanie gry rozpoczęte",
"NotificationOptionGamePlaybackStopped": "Odtwarzanie gry zatrzymane",
"NotificationOptionInstallationFailed": "Niepowodzenie instalacji",
"NotificationOptionNewLibraryContent": "Dodano nową zawartość",
"NotificationOptionPluginError": "Awaria wtyczki",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Falha na tentativa de login de {0}",
"Favorites": "Favoritos",
"Folders": "Pastas",
"Games": "Jogos",
"Genres": "Gêneros",
"HeaderAlbumArtists": "Artistas do Álbum",
"HeaderCameraUploads": "Uploads da Câmera",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Reprodução de áudio iniciada",
"NotificationOptionAudioPlaybackStopped": "Reprodução de áudio parada",
"NotificationOptionCameraImageUploaded": "Imagem de câmera enviada",
"NotificationOptionGamePlayback": "Reprodução de jogo iniciada",
"NotificationOptionGamePlaybackStopped": "Reprodução de jogo parada",
"NotificationOptionInstallationFailed": "Falha na instalação",
"NotificationOptionNewLibraryContent": "Novo conteúdo adicionado",
"NotificationOptionPluginError": "Falha de plugin",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "{0} - попытка входа неудачна",
"Favorites": "Избранное",
"Folders": "Папки",
"Games": "Игры",
"Genres": "Жанры",
"HeaderAlbumArtists": "Исп-ли альбома",
"HeaderCameraUploads": "Камеры",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Воспр-ие аудио зап-но",
"NotificationOptionAudioPlaybackStopped": "Восп-ие аудио ост-но",
"NotificationOptionCameraImageUploaded": "Произведена выкладка отснятого с камеры",
"NotificationOptionGamePlayback": "Воспр-ие игры зап-но",
"NotificationOptionGamePlaybackStopped": "Восп-ие игры ост-но",
"NotificationOptionInstallationFailed": "Сбой установки",
"NotificationOptionNewLibraryContent": "Новое содержание добавлено",
"NotificationOptionPluginError": "Сбой плагина",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Neúspešný pokus o prihlásenie z {0}",
"Favorites": "Obľúbené",
"Folders": "Priečinky",
"Games": "Hry",
"Genres": "Žánre",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Spustené prehrávanie audia",
"NotificationOptionAudioPlaybackStopped": "Zastavené prehrávanie audia",
"NotificationOptionCameraImageUploaded": "Nahraný obrázok z fotoaparátu",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Hra ukončená",
"NotificationOptionInstallationFailed": "Chyba inštalácie",
"NotificationOptionNewLibraryContent": "Pridaný nový obsah",
"NotificationOptionPluginError": "Chyba rozšírenia",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
"Favorites": "Favoriter",
"Folders": "Mappar",
"Games": "Spel",
"Genres": "Genrer",
"HeaderAlbumArtists": "Albumartister",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats",
"NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppad",
"NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp",
"NotificationOptionGamePlayback": "Spel har startats",
"NotificationOptionGamePlaybackStopped": "Spel stoppat",
"NotificationOptionInstallationFailed": "Fel vid installation",
"NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till",
"NotificationOptionPluginError": "Fel uppstod med tillägget",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "来自 {0} 的失败登入",
"Favorites": "最爱",
"Folders": "文件夹",
"Games": "游戏",
"Genres": "风格",
"HeaderAlbumArtists": "专辑作家",
"HeaderCameraUploads": "相机上传",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "音频开始播放",
"NotificationOptionAudioPlaybackStopped": "音频播放已停止",
"NotificationOptionCameraImageUploaded": "相机图片已上传",
"NotificationOptionGamePlayback": "游戏开始",
"NotificationOptionGamePlaybackStopped": "游戏停止",
"NotificationOptionInstallationFailed": "安装失败",
"NotificationOptionNewLibraryContent": "已添加新内容",
"NotificationOptionPluginError": "插件失败",

View file

@ -14,7 +14,6 @@
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"Favorites": "Favorites",
"Folders": "Folders",
"Games": "Games",
"Genres": "Genres",
"HeaderAlbumArtists": "Album Artists",
"HeaderCameraUploads": "Camera Uploads",
@ -51,8 +50,6 @@
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionPluginError": "Plugin failure",

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more